{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Config
  ( loadConfig
  , saveConfig
  , getRepoPath
  ) where

import Data.Yaml (decodeFileEither, encodeFile, FromJSON(..), ToJSON(..), (.:?), (.=), object, withObject)
import System.Directory (createDirectoryIfMissing, doesFileExist)
import System.FilePath (takeDirectory)
import Types (AppConfig(..))
import XDG (getConfigFile, getRepoDir)

instance FromJSON AppConfig where
  parseJSON :: Value -> Parser AppConfig
parseJSON = FilePath
-> (Object -> Parser AppConfig) -> Value -> Parser AppConfig
forall a. FilePath -> (Object -> Parser a) -> Value -> Parser a
withObject FilePath
"AppConfig" ((Object -> Parser AppConfig) -> Value -> Parser AppConfig)
-> (Object -> Parser AppConfig) -> Value -> Parser AppConfig
forall a b. (a -> b) -> a -> b
$ \Object
v ->
    Maybe FilePath -> AppConfig
AppConfig (Maybe FilePath -> AppConfig)
-> Parser (Maybe FilePath) -> Parser AppConfig
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser (Maybe FilePath)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"repo"

instance ToJSON AppConfig where
  toJSON :: AppConfig -> Value
toJSON (AppConfig Maybe FilePath
repo) = [Pair] -> Value
object [Key
"repo" Key -> Maybe FilePath -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe FilePath
repo]

-- | Load configuration from the config file
loadConfig :: IO AppConfig
loadConfig :: IO AppConfig
loadConfig = do
  configFile <- IO FilePath
getConfigFile
  exists <- doesFileExist configFile
  if exists
    then do
      result <- decodeFileEither configFile
      case result of
        Left ParseException
_ -> AppConfig -> IO AppConfig
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AppConfig -> IO AppConfig) -> AppConfig -> IO AppConfig
forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> AppConfig
AppConfig Maybe FilePath
forall a. Maybe a
Nothing
        Right AppConfig
config -> AppConfig -> IO AppConfig
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return AppConfig
config
    else return $ AppConfig Nothing

-- | Save configuration to the config file
saveConfig :: AppConfig -> IO ()
saveConfig :: AppConfig -> IO ()
saveConfig AppConfig
config = do
  configFile <- IO FilePath
getConfigFile
  createDirectoryIfMissing True (takeDirectory configFile)
  encodeFile configFile config

-- | Get the repository path, either from config or default
getRepoPath :: IO FilePath
getRepoPath :: IO FilePath
getRepoPath = do
  config <- IO AppConfig
loadConfig
  case configRepo config of
    Just FilePath
repo -> FilePath -> IO FilePath
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
repo
    Maybe FilePath
Nothing -> IO FilePath
getRepoDir