{-# LANGUAGE LambdaCase #-}

module Sos where

import Control.Monad.Except
import Data.ByteString      (ByteString)
import System.Exit
import Text.Megaparsec      (ParseError)

import qualified Data.ByteString.Char8 as BS

data SosException
    -- Error compiling the given regex.
    = SosRegexException
          ByteString -- pattern
          String     -- string reason for failure
    -- Error parsing a command template.
    | SosCommandParseException
          ByteString -- template
          ParseError -- failure
    -- Error applying a list of captured variables to a command template.
    | SosCommandApplyException
          [Either Int ByteString] -- template
          [ByteString]            -- captured variables
          String                  -- string reason for failure

instance Show SosException where
    show (SosRegexException pattern err) = "Error compiling regex '" ++ BS.unpack pattern ++ "': " ++ err
    show (SosCommandParseException template err) = "Error parsing command '" ++ BS.unpack template ++ "': " ++ show err
    show (SosCommandApplyException template vars err) = "Error applying template '" ++ reconstruct template ++ "' to " ++ show vars ++ ": " ++ err
      where
        reconstruct :: [Either Int ByteString] -> String
        reconstruct = concatMap
            (\case
                Left n   -> '\\' : show n
                Right bs -> BS.unpack bs)

type Sos a = ExceptT SosException IO a

runSos :: Sos a -> IO a
runSos act =
    runExceptT act >>= \case
        Left err -> do
            print err
            exitFailure
        Right x -> pure x