{-# LANGUAGE TypeApplications #-}
module Daemon.ZeroConf where

import           Startlude               hiding ( ask )

import           Control.Lens
import           Control.Effect.Reader.Labelled ( ask )
import           Control.Monad.Trans.Reader     ( withReaderT )
import           Crypto.Hash
import           Data.ByteArray                 ( convert )
import           Data.ByteArray.Encoding
import qualified Data.ByteString               as BS
import           System.FilePath.Lens

import           Foundation
import qualified Lib.Avahi                     as Avahi
import           Lib.ProductKey
import           Lib.SystemPaths

import           Settings
import qualified Lib.Algebra.Domain.AppMgr     as AppMgr2
import           Control.Carrier.Lift
import           Lib.Error

start9AgentServicePrefix :: IsString a => a
start9AgentServicePrefix = "start9-"

getStart9AgentHostname :: (HasFilesystemBase sig m, MonadIO m, ConvertText Text a) => m a
getStart9AgentHostname = do
    base   <- ask @"filesystemBase"
    suffix <-
        liftIO
        $   decodeUtf8
        .   convertToBase Base16
        .   BS.take 4
        .   convert
        .   hashWith SHA256
        .   encodeUtf8
        <$> getProductKey base
    pure . toS $ start9AgentServicePrefix <> suffix

getStart9AgentHostnameLocal :: (HasFilesystemBase sig m, MonadIO m) => m Text
getStart9AgentHostnameLocal = getStart9AgentHostname <&> (<> ".local")

publishAgentToAvahi :: ReaderT AgentCtx IO ()
publishAgentToAvahi = do
    filesystemBase     <- asks $ appFilesystemBase . appSettings
    start9AgentService <- injectFilesystemBase filesystemBase getStart9AgentHostname
    lift $ Avahi.createDaemonConf $ toS start9AgentService
    agentPort <- asks $ appPort . appSettings
    services  <- lift Avahi.listServices
    let serviceNames = view basename <$> services
    unless (start9AgentService `elem` serviceNames) $ withReaderT appSettings $ Avahi.createService
        (toS start9AgentService)
        (Avahi.WildcardsEnabled, "%h")
        "_http._tcp"
        agentPort
    lift Avahi.reload
    lift $ threadDelay 10_000_000
    tid <- asks appLanThread >>= liftIO . takeMVar
    liftIO $ killThread tid
    tid' <- liftIO $ forkIO (runM . void . runExceptT @S9Error $ AppMgr2.runAppMgrCliC AppMgr2.lanEnable)
    asks appLanThread >>= liftIO . flip putMVar tid'


