module IHP.IDE.CodeGen.MailGenerator (buildPlan, buildPlan', MailConfig (..)) where

import IHP.Prelude
import IHP.IDE.CodeGen.Types
import qualified Data.Text as Text
import qualified IHP.IDE.SchemaDesigner.Parser as SchemaDesigner
import IHP.IDE.SchemaDesigner.Types

data MailConfig = MailConfig
    { MailConfig -> Text
controllerName :: Text
    , MailConfig -> Text
applicationName :: Text
    , MailConfig -> Text
modelName :: Text
    , MailConfig -> Text
mailName :: Text
    } deriving (MailConfig -> MailConfig -> Bool
(MailConfig -> MailConfig -> Bool)
-> (MailConfig -> MailConfig -> Bool) -> Eq MailConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MailConfig -> MailConfig -> Bool
== :: MailConfig -> MailConfig -> Bool
$c/= :: MailConfig -> MailConfig -> Bool
/= :: MailConfig -> MailConfig -> Bool
Eq, Int -> MailConfig -> ShowS
[MailConfig] -> ShowS
MailConfig -> String
(Int -> MailConfig -> ShowS)
-> (MailConfig -> String)
-> ([MailConfig] -> ShowS)
-> Show MailConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MailConfig -> ShowS
showsPrec :: Int -> MailConfig -> ShowS
$cshow :: MailConfig -> String
show :: MailConfig -> String
$cshowList :: [MailConfig] -> ShowS
showList :: [MailConfig] -> ShowS
Show)

buildPlan :: Text -> Text -> Text -> IO (Either Text [GeneratorAction])
buildPlan :: Text -> Text -> Text -> IO (Either Text [GeneratorAction])
buildPlan Text
mailName Text
applicationName Text
controllerName' =
    if (Text -> Bool
forall mono. MonoFoldable mono => mono -> Bool
null Text
mailName Bool -> Bool -> Bool
|| Text -> Bool
forall mono. MonoFoldable mono => mono -> Bool
null Text
controllerName')
        then Either Text [GeneratorAction] -> IO (Either Text [GeneratorAction])
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text [GeneratorAction]
 -> IO (Either Text [GeneratorAction]))
-> Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction])
forall a b. (a -> b) -> a -> b
$ Text -> Either Text [GeneratorAction]
forall a b. a -> Either a b
Left Text
"Neither mail name nor controller name can be empty"
        else do
            [Statement]
schema <- IO (Either ByteString [Statement])
SchemaDesigner.parseSchemaSql IO (Either ByteString [Statement])
-> (Either ByteString [Statement] -> IO [Statement])
-> IO [Statement]
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                Left ByteString
parserError -> [Statement] -> IO [Statement]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
                Right [Statement]
statements -> [Statement] -> IO [Statement]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Statement]
statements
            let modelName :: Text
modelName = Text -> Text
tableNameToModelName Text
controllerName'
            let controllerName :: Text
controllerName = Text -> Text
tableNameToControllerName Text
controllerName'
            let viewConfig :: MailConfig
viewConfig = MailConfig { Text
$sel:controllerName:MailConfig :: Text
$sel:applicationName:MailConfig :: Text
$sel:modelName:MailConfig :: Text
$sel:mailName:MailConfig :: Text
mailName :: Text
applicationName :: Text
modelName :: Text
controllerName :: Text
.. }
            Either Text [GeneratorAction] -> IO (Either Text [GeneratorAction])
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text [GeneratorAction]
 -> IO (Either Text [GeneratorAction]))
-> Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction])
forall a b. (a -> b) -> a -> b
$ [GeneratorAction] -> Either Text [GeneratorAction]
forall a b. b -> Either a b
Right ([GeneratorAction] -> Either Text [GeneratorAction])
-> [GeneratorAction] -> Either Text [GeneratorAction]
forall a b. (a -> b) -> a -> b
$ [Statement] -> MailConfig -> [GeneratorAction]
buildPlan' [Statement]
schema MailConfig
viewConfig

-- E.g. qualifiedMailModuleName config "Confirmation" == "Web.Mail.Users.Confirmation"
qualifiedViewModuleName :: MailConfig -> Text -> Text
qualifiedViewModuleName :: MailConfig -> Text -> Text
qualifiedViewModuleName MailConfig
config Text
mailName =
    MailConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".Mail." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> MailConfig
config.controllerName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
ucfirst Text
mailName

buildPlan' :: [Statement] -> MailConfig -> [GeneratorAction]
buildPlan' :: [Statement] -> MailConfig -> [GeneratorAction]
buildPlan' [Statement]
schema MailConfig
config =
        let
            controllerName :: Text
controllerName = MailConfig
config.controllerName
            name :: Text
name = MailConfig
config.mailName
            singularName :: Text
singularName = MailConfig
config.modelName
            singularVariableName :: Text
singularVariableName = Text -> Text
lcfirst Text
singularName
            pluralVariableName :: Text
pluralVariableName = Text -> Text
lcfirst Text
controllerName
            nameWithSuffix :: Text
nameWithSuffix = if Text
"Mail" Text -> Text -> Bool
`isSuffixOf` Text
name
                then Text
name
                else Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Mail" --e.g. "Test" -> "TestMail"
            nameWithoutSuffix :: Text
nameWithoutSuffix = if Text
"Mail" Text -> Text -> Bool
`isSuffixOf` Text
name
                then HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
Text.replace Text
"Mail" Text
"" Text
name
                else Text
name --e.g. "TestMail" -> "Test"

            indexAction :: Text
indexAction = Text -> Text
pluralize Text
singularName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Action"

            modelFields :: [Text]
            modelFields :: [Text]
modelFields = [ Text -> Text
modelNameToTableName Text
pluralVariableName, Text
pluralVariableName ]
                    [Text] -> ([Text] -> [[Text]]) -> [[Text]]
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> (Text -> Maybe [Text]) -> [Text] -> [[Text]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ([Statement] -> Text -> Maybe [Text]
fieldsForTable [Statement]
schema)
                    [[Text]] -> ([[Text]] -> Maybe [Text]) -> Maybe [Text]
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> [[Text]] -> Maybe [Text]
forall a. [a] -> Maybe a
head
                    Maybe [Text] -> (Maybe [Text] -> [Text]) -> [Text]
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> [Text] -> Maybe [Text] -> [Text]
forall a. a -> Maybe a -> a
fromMaybe []

            mail :: Text
mail =
                Text
""
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"module " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> MailConfig -> Text -> Text
qualifiedViewModuleName MailConfig
config Text
nameWithoutSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" where\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"import " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> MailConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".View.Prelude\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"import IHP.MailPrelude\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"data " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" { " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
singularVariableName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" :: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
singularName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" }\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"instance BuildMail " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" where\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"    subject = \"Subject\"\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"    to " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" { .. } = Address { addressName = Just \"Firstname Lastname\", addressEmail = \"fname.lname@example.com\" }\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"    from = \"hi@example.com\"\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"    html " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" { .. } = [hsx|\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"        Hello World\n"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"    |]\n"
        in
            [ EnsureDirectory { $sel:directory:CreateFile :: Text
directory = MailConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Mail/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
controllerName }
            , CreateFile { $sel:filePath:CreateFile :: Text
filePath = MailConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Mail/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
controllerName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithoutSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
mail }
            , AddImport { $sel:filePath:CreateFile :: Text
filePath = MailConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Controller/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
controllerName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
"import " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> MailConfig -> Text -> Text
qualifiedViewModuleName MailConfig
config Text
nameWithoutSuffix }
            ]