module Main where

import Control.Monad.IO.Class
import Database.SQLite.Simple (Connection, open)
import Data.Monoid ((<>))
import Data.Text (pack)
import Network.HTTP.Types.Status (status404)
import Network.Wai.Middleware.Static (staticPolicy, hasPrefix)
import System.Environment (lookupEnv)
import Web.Spock
import Web.Spock.Config

import Render
import Types

respondWith :: MonadIO m => [Entry] -> ActionCtxT ctx m ()
respondWith es = do
  pref <- preferredFormat
  case pref of
    PrefJSON -> json es
    _        -> html (rPage (rEntries es))

db :: MonadIO m => DB a -> ActionCtxT Connection m a
db mote = do
  conn <- getContext
  liftIO (mote conn)

unwrap :: MonadIO m => Maybe a -> (a -> ActionCtxT ctx m ()) -> ActionCtxT ctx m ()
unwrap Nothing  _ = setStatus status404
unwrap (Just x) f = f x

main :: IO ()
main = do
  dbLoc <- maybe "test.db" id `fmap` lookupEnv "DB_LOC"
  port <- maybe 8080 read `fmap` lookupEnv "PORT"
  conn <- open dbLoc
  spockCfg <- defaultSpockCfg () PCNoDatabase ()
  runSpock port $ spock spockCfg $ prehook (return conn) $ do
    middleware $ staticPolicy (mempty <> hasPrefix "static")

    get root $ do
      html (rPage "welcome to the dictionary yo")

    get "add" $ do
      ls <- db allLanguages
      html (rPage (rAdd ls))

    get "search" $ do
      html (rPage rSearch)

    get ("lang") $ do
      ls <- db allLanguages
      html (rPage (rLangList ls))

    get ("lang" <//> var) $ \ lang -> do
      es <- db (getWordsByLanguage lang)
      respondWith es

    get "word" $ do
      es <- db getAllWords
      respondWith es
    post "word" $ do
      ps <- paramsToEntry <$> params
      unwrap ps $ \ e -> do
        i <- db (addWord e)
        redirect (pack ("/word/" ++ show i))

    get ("word" <//> var) $ \ w -> do
      eM <- db (getWordById w)
      unwrap eM $ \ e -> respondWith [e]
    post ("word" <//> var) $ \ w -> do
      ps <- paramsToEntry <$> params
      unwrap ps $ \ e -> do
          db (updateWord w e)
          redirect (pack ("/word/" ++ show w))

    get ("word" <//> var <//> "edit") $ \ w -> do
      eM <- db (getWordById w)
      ls <- db allLanguages
      unwrap eM $ html . rPage . rEdit w ls

    get ("word" <//> "search" <//> var) $ \ t -> do
      db (searchAll t) >>= respondWith

    get ("word" <//> "search" <//> "by-word" <//> var) $ \ t -> do
      db (searchWord t) >>= respondWith

    get ("word" <//> "search" <//> "by-meaning" <//> var) $ \ t -> do
      db (searchMeaning t) >>= respondWith
