{-# LANGUAGE NumericUnderscores #-}
module GitHUD.Daemon.Runner (
    runDaemon
    ) where

import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.MVar (MVar, readMVar, newMVar, swapMVar)
import qualified Control.Exception as E
import Control.Monad (when, forever, void, unless)
import qualified Data.ByteString.UTF8 as BSU
import Data.Maybe (fromMaybe)
import System.Directory (removeFile)
import System.Posix.Daemon (isRunning, runDetached, Redirection(DevNull, ToFile))
import System.Posix.Files (fileExist)

import GitHUD.Config.Types
import GitHUD.Git.Command
import GitHUD.Daemon.Network

runDaemon :: Config
          -> Maybe String
          -> IO ()
runDaemon config mArg = do
  let pathToPoll = (fromMaybe "/" mArg)
  ensureDaemonRunning config socketFile pathToPoll
  void $ sendOnSocket socketFile pathToPoll
  where
    socketFile = confGithuddSocketFilePath config

ensureDaemonRunning :: Config
                    -> FilePath
                    -> FilePath
                    -> IO ()
ensureDaemonRunning config socketPath pathToPoll = do
  running <- isRunning pidFilePath
  unless running $ do
    socketExists <- fileExist socketPath
    when socketExists (removeFile socketPath)
    removeLogFile stdoutFile
    runDetached (Just pidFilePath) stdoutFile (daemon delaySec pathToPoll socketPath)
  where
    stdoutFile = confGithuddLogFilePath config
    pidFilePath = confGithuddPidFilePath config
    delaySec = confGithuddSleepSeconds config

removeLogFile :: Redirection
              -> IO ()
removeLogFile DevNull = return ()
removeLogFile (ToFile file) = do
    debugFileExists <- fileExist file
    when debugFileExists (removeFile file)

daemon :: Int
       -> FilePath
       -> FilePath
       -> IO ()
daemon delaySec path socket = do
  pathToPoll <- newMVar path
  forkIO $ socketClient socket pathToPoll
  forever $ fetcher delaySec socket pathToPoll

socketClient :: FilePath
             -> MVar String
             -> IO ()
socketClient socketPath mvar =
  fromSocket socketPath withMessage
    where
      withMessage msg = do
        putStrLn $ "Switching to poll " ++ msg
        swapMVar mvar msg

fetcher :: Int
        -> FilePath
        -> MVar String
        -> IO ()
fetcher delaySec socketPath mvar = do
  path <- readMVar mvar
  gitCmdFetch path
  threadDelay $ delaySec * 1_000_000
  return ()