module Main where import Database.PostgreSQL.Simple import Control.Monad (forever, forM_) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Reader (runReaderT, ask) import Control.Exception (catch, SomeException) import Data.Maybe (isJust, fromJust) import Data.Time (Day) import Data.Time.Format (parseTimeM, defaultTimeLocale) import Data.Time.Calendar (Day) import User import Reservation import Session import Types import Database main :: IO () main = do conn <- catch connectDB handleSqlError initializeDB conn addAdminUser conn putStrLn "Welcome to the Ticket Booking System!" user <- loginOrRegister conn runSession user $ appLoop conn user loginOrRegister :: Connection -> IO User loginOrRegister conn = do putStrLn "1) Register 2) Login" choice <- getLine case choice of "1" -> do putStrLn "Enter your name:" name <- getLine putStrLn "Enter your password:" password <- getLine registerUser conn name password loginOrRegister conn "2" -> do putStrLn "Enter your name:" name <- getLine putStrLn "Enter your password:" password <- getLine mUser <- loginUser conn name password if isJust mUser then return (fromJust mUser) else do putStrLn "Invalid credentials, please try again." loginOrRegister conn _ -> do putStrLn "Invalid option, please try again." loginOrRegister conn appLoop :: Connection -> User -> Session () appLoop conn user = forever $ do lift $ putStrLn $ "Logged in as " ++ userName user ++ ". " isAdminResult <- liftIO $ User.isAdmin conn (userName user) if isAdminResult == Just True then adminMenu else userMenu where adminMenu = do lift $ putStrLn "Admin Menu:" lift $ putStrLn "1) Add event 2) View events 3) Exit" choice <- lift getLine case choice of "1" -> do lift $ putStrLn "Enter event name:" eventName <- lift getLine lift $ putStrLn "Enter event date (YYYY-MM-DD):" eventDateStr <- lift getLine case parseEventDate eventDateStr of Just eventDate -> if isValidEventDate eventDate then do lift $ addEvent conn user eventName eventDate else lift $ putStrLn "Invalid event date. Please enter a date between 2024-05-27 and 2026-01-01, with a valid month (01-12) and day (01-31)." Nothing -> lift $ putStrLn "Invalid date format. Please enter the date in the format YYYY-MM-DD." "2" -> do events <- lift $ getEvents conn lift $ printEvents events "3" -> liftIO $ putStrLn "Exiting..." >> error "Program terminated by user" _ -> lift $ putStrLn "Invalid option. Please try again." userMenu = do lift $ putStrLn "User Menu:" lift $ putStrLn "1) Add reservation 2) View reservations 3) View events 4) Check event attendees 5) Exit" choice <- lift getLine case choice of "1" -> do events <- lift $ getEvents conn lift $ printEvents events lift $ putStrLn "Enter event ID:" eventIdStr <- lift getLine let eventId = read eventIdStr :: Int lift $ addReservation conn (userId user) eventId "2" -> do reservations <- lift $ getReservations conn (userId user) lift $ putStrLn "Your reservations:" lift $ forM_ reservations (printReservation conn) "3" -> do events <- lift $ getEvents conn lift $ printEvents events "4" -> do events <- lift $ getEvents conn lift $ printEvents events lift $ putStrLn "Enter event ID to check attendees:" eventIdStr <- lift getLine let eventId = read eventIdStr :: Int attendees <- lift $ getUsersForEvent conn eventId lift $ putStrLn $ "Attendees for event " ++ show eventId ++ ":" lift $ forM_ attendees $ \(userId, userName) -> putStrLn $ show userName "5" -> liftIO $ putStrLn "Exiting..." >> error "Program terminated by user" _ -> lift $ putStrLn "Invalid option. Please try again." handleSqlError :: SomeException -> IO Connection handleSqlError e = do putStrLn $ "Database connection error: " ++ show e error "Failed to connect to the database" printEvents :: [Event] -> IO () printEvents events = do putStrLn "Available events:" forM_ events $ \event -> putStrLn $ "Event ID: " ++ show (eventId event) ++ ", Name: " ++ eventName event ++ ", Date: " ++ show (eventDate event) printReservation :: Connection -> Reservation -> IO () printReservation conn reservation = do event <- getEvent conn (reservationEventId reservation) putStrLn $ "Event Name: " ++ eventName event ++ ", Event Date: " ++ show (eventDate event)