{-# OPTIONS_GHC -Wall -Werror #-}

{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
{-# LANGUAGE Safe                         #-}

--------------------------------------------------------------------------------

-- |
-- Copyright  : (c) 2026 SPISE MISU ApS
-- License    : SSPL-1.0 OR AGPL-3.0-only
-- Maintainer : SPISE MISU <mail+hackage@spisemisu.com>
-- Stability  : experimental

--------------------------------------------------------------------------------

module Internal.LLM
  ( UUID (..)
  , Root (..)
  , Filter (..)
  , Mode (..)
  , Chit (..)
  , Chat
  , History (..)
  , Mask (..)
  , File (..)
  , Files (..)
  , FileLine
  , FilePaths (..)
  , AbsoluteFilePath (..)
  , Template (..)
  , modes
  , tpl2xmls
  )
where

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

newtype UUID = UUID String

newtype Root = Root FilePath deriving Root -> Root -> Bool
(Root -> Root -> Bool) -> (Root -> Root -> Bool) -> Eq Root
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Root -> Root -> Bool
== :: Root -> Root -> Bool
$c/= :: Root -> Root -> Bool
/= :: Root -> Root -> Bool
Eq

newtype Filter = Filter String

data Mode
  = Auto
  | Chat
  | Code
  | Docs
  | Echo
  | Plan
  | Test
  deriving (Mode
Mode -> Mode -> Bounded Mode
forall a. a -> a -> Bounded a
$cminBound :: Mode
minBound :: Mode
$cmaxBound :: Mode
maxBound :: Mode
Bounded, Int -> Mode
Mode -> Int
Mode -> [Mode]
Mode -> Mode
Mode -> Mode -> [Mode]
Mode -> Mode -> Mode -> [Mode]
(Mode -> Mode)
-> (Mode -> Mode)
-> (Int -> Mode)
-> (Mode -> Int)
-> (Mode -> [Mode])
-> (Mode -> Mode -> [Mode])
-> (Mode -> Mode -> [Mode])
-> (Mode -> Mode -> Mode -> [Mode])
-> Enum Mode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Mode -> Mode
succ :: Mode -> Mode
$cpred :: Mode -> Mode
pred :: Mode -> Mode
$ctoEnum :: Int -> Mode
toEnum :: Int -> Mode
$cfromEnum :: Mode -> Int
fromEnum :: Mode -> Int
$cenumFrom :: Mode -> [Mode]
enumFrom :: Mode -> [Mode]
$cenumFromThen :: Mode -> Mode -> [Mode]
enumFromThen :: Mode -> Mode -> [Mode]
$cenumFromTo :: Mode -> Mode -> [Mode]
enumFromTo :: Mode -> Mode -> [Mode]
$cenumFromThenTo :: Mode -> Mode -> Mode -> [Mode]
enumFromThenTo :: Mode -> Mode -> Mode -> [Mode]
Enum, Mode -> Mode -> Bool
(Mode -> Mode -> Bool) -> (Mode -> Mode -> Bool) -> Eq Mode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Mode -> Mode -> Bool
== :: Mode -> Mode -> Bool
$c/= :: Mode -> Mode -> Bool
/= :: Mode -> Mode -> Bool
Eq, ReadPrec [Mode]
ReadPrec Mode
Int -> ReadS Mode
ReadS [Mode]
(Int -> ReadS Mode)
-> ReadS [Mode] -> ReadPrec Mode -> ReadPrec [Mode] -> Read Mode
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Mode
readsPrec :: Int -> ReadS Mode
$creadList :: ReadS [Mode]
readList :: ReadS [Mode]
$creadPrec :: ReadPrec Mode
readPrec :: ReadPrec Mode
$creadListPrec :: ReadPrec [Mode]
readListPrec :: ReadPrec [Mode]
Read, Int -> Mode -> ShowS
[Mode] -> ShowS
Mode -> FilePath
(Int -> Mode -> ShowS)
-> (Mode -> FilePath) -> ([Mode] -> ShowS) -> Show Mode
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Mode -> ShowS
showsPrec :: Int -> Mode -> ShowS
$cshow :: Mode -> FilePath
show :: Mode -> FilePath
$cshowList :: [Mode] -> ShowS
showList :: [Mode] -> ShowS
Show)

data Chit =
  Chit
    { Chit -> [FilePath]
prev :: ![String]
    , Chit -> [FilePath]
next :: ![String]
    }

type Chat = [String]

data History =
  History
    { History -> Chit
chit :: !Chit
    , History -> [FilePath]
chat :: !Chat
    }

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

newtype Mask = Mask [String]

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

type Markdown = String

type FileLine = String

newtype File = File (FilePath, [FileLine])

--------------------------------------------------------------------------------

newtype Files = Files [File]

instance Semigroup Files where
  Files [File]
xs <> :: Files -> Files -> Files
<> Files [File]
ys =
    [File] -> Files
Files ([File]
xs [File] -> [File] -> [File]
forall a. [a] -> [a] -> [a]
++ [File]
ys)

instance Monoid Files where
  mempty :: Files
mempty = [File] -> Files
Files []

--------------------------------------------------------------------------------

newtype AbsoluteFilePath = AbsoluteFilePath FilePath

--------------------------------------------------------------------------------

-- NOTE: Then use `mconcat` to combine

data FilePaths = FilePaths { FilePaths -> [FilePath]
filePaths :: [FilePath] }

instance Semigroup FilePaths where
  FilePaths [FilePath]
xs <> :: FilePaths -> FilePaths -> FilePaths
<> FilePaths [FilePath]
ys =
    [FilePath] -> FilePaths
FilePaths ([FilePath]
xs [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
ys)

instance Monoid FilePaths where
  mempty :: FilePaths
mempty = [FilePath] -> FilePaths
FilePaths []

--------------------------------------------------------------------------------

data Template =
  Template
    { Template -> FilePath
purpose      :: !String
    , Template -> [FilePath]
instructions :: ![String]
    , Template -> [FilePath]
examples     :: ![Markdown]
    , Template -> [File]
files        :: ![File]
    }

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

modes :: [Mode]
modes :: [Mode]
modes =
 [ Mode
forall a. Bounded a => a
minBound .. Mode
forall a. Bounded a => a
maxBound ]

tpl2xmls
  :: Template
  -> [String]
tpl2xmls :: Template -> [FilePath]
tpl2xmls Template
tpl =
  [ ( if Bool
eis Bool -> Bool -> Bool
&& Bool
ees Bool -> Bool -> Bool
&& Bool
efs then
        FilePath
pur
      else
        FilePath
"<purpose>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
pur FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"</purpose>"
    ) FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
    ( if Bool
eis then
        []
      else
        FilePath
"<instructions>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        FilePath
tis FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        FilePath
"</instructions>"
    ) FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
    ( if Bool
ees then
        []
      else
        FilePath
"<examples>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        FilePath
tes FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        FilePath
"</examples>"
    ) FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
    ( if Bool
efs then
        []
      else
        FilePath
"<files>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        ((Int, File) -> FilePath) -> [(Int, File)] -> FilePath
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int, File) -> FilePath
forall {a}. Show a => (a, File) -> FilePath
aux [(Int, File)]
tfs FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
        FilePath
"</files>"
    )
  ]
  where
    pur :: FilePath
pur =
      Template -> FilePath
purpose Template
tpl FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      ( if Bool
eis then
          []
        else
          FilePath
". Follow the specified `instructions`"
      ) FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      ( if Bool
ees then
          []
        else
          FilePath
". Output MUST match scaffolding from provided `examples`"
      ) FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      ( if Bool
efs then
          []
        else
          FilePath
". Apply to each of the `files`"
      )
    eis :: Bool
eis = FilePath -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
tis
    ees :: Bool
ees = FilePath -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
tes
    efs :: Bool
efs = [(Int, File)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Int, File)]
tfs
    tis :: FilePath
tis =
      ShowS -> [FilePath] -> FilePath
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\ FilePath
x -> FilePath
"<instruction>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
x FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"</instruction>")
      ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ Template -> [FilePath]
instructions Template
tpl
    tes :: FilePath
tes =
      ShowS -> [FilePath] -> FilePath
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\ FilePath
x -> FilePath
"<example>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
x FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"</example>")
      ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ Template -> [FilePath]
examples Template
tpl
    tfs :: [(Int, File)]
tfs = [Int] -> [File] -> [(Int, File)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 :: Int ..] ([File] -> [(Int, File)]) -> [File] -> [(Int, File)]
forall a b. (a -> b) -> a -> b
$ Template -> [File]
files Template
tpl
    aux :: (a, File) -> FilePath
aux (a
i, File (FilePath
src, [FilePath]
ls)) =
      FilePath
"<file index=\"" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> FilePath
forall a. Show a => a -> FilePath
show a
i FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"\">" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      FilePath
"<source>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
src FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"</source>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      FilePath
"<content>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ [FilePath] -> FilePath
unlines [FilePath]
ls FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"</content>" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++
      FilePath
"</file>"