content: {-# LANGUAGE OverloadedStrings #-}
  
  -- |
  -- Module      : Main
  -- Description : Main entry point for the Clod application
  -- Copyright   : (c) Fuzz Leonard, 2025
  -- License     : MIT
  -- Maintainer  : fuzz@fuzz.ink
  -- Stability   : experimental
  --
  -- This module provides the main CLI interface for the Clod application.
  
  module Main where
  
  import Options.Applicative
  import System.Exit (exitFailure)
  import System.Directory (createDirectoryIfMissing, getCurrentDirectory, getTemporaryDirectory, 
                           doesFileExist, doesDirectoryExist)
  import System.FilePath ((</>))
  import System.IO (stderr, hPutStrLn)
  import Data.Time (getCurrentTime)
  import Data.Time.Format (formatTime, defaultTimeLocale)
  import Data.Hashable (hash)
  import Control.Exception (try, IOException)
  import Data.List (isInfixOf)
  import Data.Version (showVersion)
  import qualified Paths_clod as Meta
  
  import Clod.Core (runClodApp)
  import Clod.Types (ClodConfig(..))
  import qualified Clod.Types as T
  
  -- | Command line options for Clod
  data Options = Options
    { optStagingDir  :: String   -- ^ Directory where files will be staged (test mode only)
    , optAllFiles    :: Bool     -- ^ Import all files (otherwise imports only modified files)
    , optTestMode    :: Bool     -- ^ Run in test mode
    , optVerbose     :: Bool     -- ^ Enable verbose output
    , optFlush       :: Bool     -- ^ Flush stale entries from the database
    , optLast        :: Bool     -- ^ Use previous staging directory
    } deriving (Show)
  
  -- | Parser for command line options
  optionsParser :: Parser Options
  optionsParser = Options
    <$> strOption
        ( long "staging-dir"
       <> short 'd'
       <> metavar "DIR"
       <> help "Directory where files will be staged for Claude (only used in test mode)"
       <> value ""
       <> showDefault )
    <*> switch
        ( long "all"
       <> short 'a'
       <> help "Import all files (respecting .gitignore)" )
    <*> switch
        ( long "test"
       <> short 't'
       <> help "Run in test mode" )
    <*> switch
        ( long "verbose"
       <> short 'v'
       <> help "Enable verbose output" )
    <*> switch
        ( long "flush"
       <> short 'f'
       <> help "Flush missing entries from the database" )
    <*> switch
        ( long "last"
       <> short 'l'
       <> help "Use previous staging directory" )
  
  -- | Main entry point
  main :: IO ()
  main = do
    options <- execParser opts
    
    -- Create a minimal configuration for the effects system
    currentDir <- getCurrentDirectory
    
    -- For config dir: use local .clod in project directory
    let configDirPath = currentDir </> ".clod"
    
    -- For staging directory: use system temp directory
    tempDir <- getTemporaryDirectory
    let stagingDirBase = tempDir </> "clod-staging"
    
    -- Create a unique staging directory for this run
    timestamp <- formatTime defaultTimeLocale "%Y%m%d%H%M%S" <$> getCurrentTime
    let uniqueId = take 8 $ show $ hash $ currentDir ++ timestamp
    let stagingDirPath = if null (optStagingDir options) 
                      then stagingDirBase </> uniqueId
                      else optStagingDir options
    
    -- Load previous staging directory if in "last" mode
    let dbPath = configDirPath </> "db.dhall"
    previousDir <- if optLast options
                   then do
                     dbExists <- doesFileExist dbPath
                     if dbExists
                       then do
                         -- Try to read the database to get the previous staging dir
                         edb <- try $ do
                           content <- readFile dbPath
                           -- Look for lastStagingDir pattern in the Dhall file
                           let contentLines = filter (\l -> "lastStagingDir" `isInfixOf` l) $ lines content
                           case contentLines of
                             (line:_) -> 
                               if "None" `isInfixOf` line
                                 then return Nothing 
                                 else do
                                   -- Extract path from "Some ./path/to/dir" format
                                   let parts = words line
                                   let path = if length parts > 2 
                                              then read (last parts) :: String
                                              else ""
                                   return $ if null path then Nothing else Just path
                             _ -> return Nothing
                           :: IO (Either IOException (Maybe FilePath))
                         case edb of
                           Left _ -> return Nothing
                           Right mbDir -> return mbDir
                       else return Nothing
                   else return Nothing
    
    -- Use previous staging dir if requested and available
    finalStagingPath <- case (optLast options, previousDir) of
                          (True, Just prevDir) -> do
                            -- Check if the previous directory still exists
                            dirExists <- doesDirectoryExist prevDir
                            return $ if dirExists 
                                     then prevDir
                                     else stagingDirPath
                          _ -> return stagingDirPath
    
    do
        -- Create staging directory if it doesn't exist
        createDirectoryIfMissing True finalStagingPath
        createDirectoryIfMissing True configDirPath
        
        -- Create a basic config
        let config = ClodConfig "" "" "" "" "" "" Nothing False False False False []
              T.& T.projectPath T..~ currentDir
              T.& T.stagingDir T..~ finalStagingPath
              T.& T.configDir T..~ configDirPath
              T.& T.databaseFile T..~ dbPath
              T.& T.timestamp T..~ ""  -- Will be set internally
              T.& T.currentStaging T..~ finalStagingPath
              T.& T.previousStaging T..~ previousDir
              T.& T.testMode T..~ optTestMode options
              T.& T.verbose T..~ optVerbose options
              T.& T.flushMode T..~ optFlush options
              T.& T.lastMode T..~ optLast options
              T.& T.ignorePatterns T..~ []  -- Will be populated
        
        -- Run with effects system
        result <- runClodApp config 
                    (optStagingDir options)
                    (optVerbose options)
                    (optAllFiles options)
        
        case result of
          Left err -> do
            hPutStrLn stderr $ "Error: " ++ show err
            exitFailure
          Right _ -> return ()
    where
      opts = info (optionsParser <**> helper <**> version)
        ( fullDesc
       <> progDesc "Prepare files from a git repository for upload to Claude's Project Knowledge"
       <> header "clod - Claude Git Project File Uploader" )
      version = infoOption (showVersion Meta.version)
        ( long "version"
       <> short 'V'
       <> help "Show version information" )
  