content: {-# LANGUAGE OverloadedStrings #-}
  {-# OPTIONS_GHC -Wno-unused-top-binds #-}
  
  module Knives.WireGuard where
  
  import Utils (systemctl)
  import CommandLine
  -- import System.IO
  -- import System.Process
  import System.Directory (getDirectoryContents)
  import System.FilePath (dropExtension, takeExtension)
  import Control.Monad (when)
  import Data.List
  
  knifeWireGuard :: WireGuardOptions -> IO ()
  knifeWireGuard WireGuardOptions { listWGs
                                  , activateWG
                                  , enableWG
                                  , deactivateWG
                                  , disableWG
                                  , reactivateWG}
    | checkMutualExclusivity = do
        wgs <- wgList
        ss  <- wgStatus wgs
        when listWGs $ putStrLn $ formatStatus ss
        case (activateWG , enableWG , deactivateWG , disableWG , reactivateWG) of
              (Just vpn  , Nothing  , False        , False     , False) -> activate vpn
              (Nothing   , Just vpn , False        , False     , False) -> enable vpn
              (Nothing   , Nothing  , True         , False     , False) -> deactivate
              (Nothing   , Nothing  , False        , True      , False) -> disable
              (Nothing   , Nothing  , False        , False     , True ) -> reactivate
              _                        -> return ()
    | otherwise = putStrLn "Options aside from --list or -l are mutually exclusive"
    where
      wgDir = "/etc/wireguard/"
  
      wgList :: IO [String]
      wgList = do
        rawlist <- getDirectoryContents wgDir
        let wgconf = filter (\f -> takeExtension f == ".conf") rawlist
        let wgs    = map (\f -> dropExtension f) wgconf
        return wgs
        
      wgStatus :: [String] -> IO [(String, String, String, Bool, Bool)]
      wgStatus wgs = do
        let quick = map (\w -> vpn2wg w) wgs
        let cmd_a   = ["is-active"]  <> quick
        let cmd_e   = ["is-enabled"] <> quick
        stats_a <- systemctl cmd_a
        stats_e <- systemctl cmd_e
        return $ [(wg
                  , sact
                  , sena
                  , sact == "active"
                  , sena == "enabled") | (wg, sact, sena) <- zip3 wgs stats_a stats_e ]
  
      formatStatus :: [(String, String, String, Bool, Bool)] -> String
      formatStatus wss = intercalate "\n" [w <> ": " <> sa <> " " <> se |(w, sa, se, _, _) <- wss]
  
      checkMutualExclusivity = check [ activateWG /= Nothing
                                     , enableWG   /= Nothing
                                     , deactivateWG
                                     , disableWG
                                     , reactivateWG]
  
      check bs   = (length $ filter id bs) `elem` [0, 1]
      vpn2wg vpn = "wg-quick@" <> vpn
      
      activate :: String -> IO ()
      activate vpn = do
        _ <- systemctl ["start", vpn2wg vpn]
        return ()
  
      enable :: String -> IO ()
      enable vpn = do
        _ <- systemctl ["enable", "--now", vpn2wg vpn]
        return ()
      
      deactivate :: IO ()
      deactivate   = do
        awgs <- activeWG
        mapM_ (\w -> systemctl $ ["stop"] <> [vpn2wg w]) awgs
        return ()
  
      disable :: IO ()
      disable = do
        awgs <- enabledWG
        mapM_ (\w -> systemctl $ ["disable", "--now"] <> [vpn2wg w]) awgs
        return ()
  
  
      reactivate :: IO ()
      reactivate   = do
        awgs <- activeWG
        mapM_ (\w -> systemctl $ ["restart"] <>  [vpn2wg w]) awgs
        return()
  
      activeWG :: IO [String]
      activeWG = do
        wgl <- wgList
        wgs <- wgStatus wgl
        return [s | (s, _, _, a, _) <- wgs, a]
  
      enabledWG :: IO [String]
      enabledWG = do
        wgl <- wgList
        wgs <- wgStatus wgl
        return [s | (s, _, _, _, e) <- wgs, e]
  