{-# LANGUAGE OverloadedStrings #-}
-- | Monad utilities for SD-JWT operations.
--
-- This module provides ExceptT-based utilities for cleaner error handling
-- in IO contexts.
module SDJWT.Internal.Monad
  ( SDJWTIO
  , runSDJWTIO
  , eitherToExceptT
  , partitionAndHandle
  ) where

import SDJWT.Internal.Types (SDJWTError)
import Control.Monad.Except (ExceptT, runExceptT, throwError)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Either (partitionEithers)

-- | Type alias for IO operations that can fail with SDJWTError.
type SDJWTIO = ExceptT SDJWTError IO

-- | Run an SDJWTIO computation.
runSDJWTIO :: SDJWTIO a -> IO (Either SDJWTError a)
runSDJWTIO :: forall a. SDJWTIO a -> IO (Either SDJWTError a)
runSDJWTIO = ExceptT SDJWTError IO a -> IO (Either SDJWTError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT

-- | Convert an Either to ExceptT.
eitherToExceptT :: Monad m => Either SDJWTError a -> ExceptT SDJWTError m a
eitherToExceptT :: forall (m :: * -> *) a.
Monad m =>
Either SDJWTError a -> ExceptT SDJWTError m a
eitherToExceptT = (SDJWTError -> ExceptT SDJWTError m a)
-> (a -> ExceptT SDJWTError m a)
-> Either SDJWTError a
-> ExceptT SDJWTError m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either SDJWTError -> ExceptT SDJWTError m a
forall a. SDJWTError -> ExceptT SDJWTError m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError a -> ExceptT SDJWTError m a
forall a. a -> ExceptT SDJWTError m a
forall (m :: * -> *) a. Monad m => a -> m a
return

-- | Handle partitionEithers results in ExceptT context.
handlePartitionEithers
  :: Monad m
  => [SDJWTError]  -- ^ Errors from partitionEithers
  -> [a]  -- ^ Successes from partitionEithers
  -> ([a] -> ExceptT SDJWTError m b)  -- ^ Success handler
  -> ExceptT SDJWTError m b
handlePartitionEithers :: forall (m :: * -> *) a b.
Monad m =>
[SDJWTError]
-> [a] -> ([a] -> ExceptT SDJWTError m b) -> ExceptT SDJWTError m b
handlePartitionEithers [SDJWTError]
errors [a]
successes [a] -> ExceptT SDJWTError m b
handler =
  case [SDJWTError]
errors of
    (SDJWTError
err:[SDJWTError]
_) -> SDJWTError -> ExceptT SDJWTError m b
forall a. SDJWTError -> ExceptT SDJWTError m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError SDJWTError
err
    [] -> [a] -> ExceptT SDJWTError m b
handler [a]
successes

-- | Helper to partition Either results and handle in ExceptT context.
partitionAndHandle
  :: Monad m
  => [Either SDJWTError a]  -- ^ List of Either results
  -> ([a] -> ExceptT SDJWTError m b)  -- ^ Success handler
  -> ExceptT SDJWTError m b
partitionAndHandle :: forall (m :: * -> *) a b.
Monad m =>
[Either SDJWTError a]
-> ([a] -> ExceptT SDJWTError m b) -> ExceptT SDJWTError m b
partitionAndHandle [Either SDJWTError a]
results [a] -> ExceptT SDJWTError m b
handler =
  let ([SDJWTError]
errors, [a]
successes) = [Either SDJWTError a] -> ([SDJWTError], [a])
forall a b. [Either a b] -> ([a], [b])
partitionEithers [Either SDJWTError a]
results
  in [SDJWTError]
-> [a] -> ([a] -> ExceptT SDJWTError m b) -> ExceptT SDJWTError m b
forall (m :: * -> *) a b.
Monad m =>
[SDJWTError]
-> [a] -> ([a] -> ExceptT SDJWTError m b) -> ExceptT SDJWTError m b
handlePartitionEithers [SDJWTError]
errors [a]
successes [a] -> ExceptT SDJWTError m b
handler