{-# LANGUAGE OverloadedStrings #-}
module Elm.Encoder (toElmEncoderSource, toElmEncoderSourceWith)
       where

import           Control.Monad.Reader
import           Data.Text
import           Elm.Common
import           Elm.Type
import           Formatting

render :: ElmTypeExpr -> Reader Options Text

render (TopLevel (DataType d t)) =
    sformat
        (stext % " : " % stext % " -> Value\n" % stext % " x =" % stext)
        fnName
        d
        fnName <$>
    render t
  where
    fnName = sformat ("encode" % stext) d

render (DataType d _) = return $ sformat ("encode" % stext) d

render (Record _ t) =
  sformat ("\n    object\n        [ " % stext % "\n        ]") <$> render t

render (Product (Primitive "List") (Primitive "Char")) =
  render (Primitive "String")

render (Product (Primitive "List") t) =
  sformat ("(list << List.map " % stext % ")") <$> render t

render (Product (Primitive "Maybe") t) =
  sformat ("(Maybe.withDefault null << Maybe.map " % stext % ")") <$> render t

render (Tuple2 x y) =
  do bodyX <- render x
     bodyY <- render y
     return $ sformat ("tuple2 " % stext % " " % stext) bodyX bodyY

render (Dict x y) =
  do bodyX <- render x
     bodyY <- render y
     return $ sformat ("dict " % stext % " " % stext) bodyX bodyY

render (Product x y) =
  do bodyX <- render x
     bodyY <- render y
     return $ sformat (stext % "\n        , " % stext) bodyX bodyY

render (Selector n t) =
  do fieldModifier <- asks fieldLabelModifier
     typeBody <- render t
     return $ sformat ("( \"" % stext % "\", " % stext % " x." % stext % " )") (fieldModifier n) typeBody n

render  (Primitive "String") = return "string"
render  (Primitive "Int") = return "int"
render  (Primitive "Double") = return "float"
render  (Primitive "Float") = return "float"
render  (Primitive "Date") = return "(string << toISOString)"
render  (Primitive "Bool") = return "bool"
render  (Field t) = render t

toElmEncoderSourceWith :: ElmType a => Options -> a -> Text
toElmEncoderSourceWith options x = runReader (render . TopLevel $ toElmType x) options

toElmEncoderSource :: ElmType a => a -> Text
toElmEncoderSource = toElmEncoderSourceWith defaultOptions