{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}

{- |
Description :  Haskell server for Facebook's react-tutorial.
Copyright   :  (c) Alexander Berntsen 2016
License     :  AGPL-3

Maintainer  :  alexander@plaimi.net
-}


import Control.Monad.IO.Class (liftIO)
import Data.ByteString (readFile)
import Data.ByteString.Lazy (fromStrict, writeFile)
import Data.Aeson (FromJSON, ToJSON, decode)
import Data.Aeson.Encode.Pretty (Config (Config), encodePretty', keyOrder)
import Data.Time.Clock.POSIX (getPOSIXTime)
import GHC.Generics (Generic)
import Web.Scotty (ActionM, ScottyM, file, get, json, param, post, setHeader
                  ,scotty)

import Prelude hiding (id, readFile, writeFile)

data Comment = C { id :: Int, author :: String, text :: String }
  deriving (Generic, Show)

instance FromJSON Comment
instance ToJSON Comment

postComments :: ActionM ()
postComments = do
  cs <- readComments
  i <- liftIO $ round . (* 1000) <$> getPOSIXTime
  a <- param "author"
  t <- param "text"
  let cs' = (++ [C { id = i, author = a, text = t }]) <$> cs
  liftIO $ writeFile "comments.json"
         $ encodePretty' (Config 4 (keyOrder ["id", "author", "text"])) cs'
  presentComments cs'

getComments :: ActionM ()
getComments = presentComments =<< readComments

presentComments :: Maybe [Comment] -> ActionM ()
presentComments cs = do
  setHeader "Cache-Control"               "no-cache"
  setHeader "Access-Control-Allow-Origin" "*"
  json cs

readComments :: ActionM (Maybe [Comment])
readComments = do
  f <- liftIO $ readFile "comments.json"
  let cs = decode (fromStrict f) :: Maybe [Comment]
  pure cs

app :: ScottyM ()
app = do
  get "/"                   $ setHeader "Content-Type" "text/html"
                           >> file "public/index.html"
  get "/css/base.css"       $ file "public/css/base.css"
  get "/scripts/example.js" $ file "public/scripts/example.js"
  get "/api/comments"         getComments
  post "/api/comments"        postComments

main :: IO ()
main = scotty 3000 app