{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}

module Scientist.Result
  ( Result(..)
  , resultValue
  , resultDetails
  , ResultDetails(..)
  , resultDetailsCandidate
  , ResultControl(..)
  , ResultCandidate(..)
  ) where

import Prelude

import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NE
import Data.Text (Text)
import Scientist.Control
import Scientist.Duration
import UnliftIO.Exception (SomeException)

data Result c a b
    = ResultSkipped (Control a)
    | ResultMatched (ResultDetails c a b)
    | ResultIgnored (ResultDetails c a b)
    | ResultMismatched (ResultDetails c a b)

resultValue :: Result c a b -> a
resultValue :: Result c a b -> a
resultValue = \case
  ResultSkipped (Control a
a) -> a
a
  ResultMatched ResultDetails c a b
rd -> ResultDetails c a b -> a
forall c a b. ResultDetails c a b -> a
resultDetailsControlValue ResultDetails c a b
rd
  ResultIgnored ResultDetails c a b
rd -> ResultDetails c a b -> a
forall c a b. ResultDetails c a b -> a
resultDetailsControlValue ResultDetails c a b
rd
  ResultMismatched ResultDetails c a b
rd -> ResultDetails c a b -> a
forall c a b. ResultDetails c a b -> a
resultDetailsControlValue ResultDetails c a b
rd

resultDetails :: Result c a b -> Maybe (ResultDetails c a b)
resultDetails :: Result c a b -> Maybe (ResultDetails c a b)
resultDetails = \case
  ResultSkipped{} -> Maybe (ResultDetails c a b)
forall a. Maybe a
Nothing
  ResultMatched ResultDetails c a b
rd -> ResultDetails c a b -> Maybe (ResultDetails c a b)
forall a. a -> Maybe a
Just ResultDetails c a b
rd
  ResultIgnored ResultDetails c a b
rd -> ResultDetails c a b -> Maybe (ResultDetails c a b)
forall a. a -> Maybe a
Just ResultDetails c a b
rd
  ResultMismatched ResultDetails c a b
rd -> ResultDetails c a b -> Maybe (ResultDetails c a b)
forall a. a -> Maybe a
Just ResultDetails c a b
rd

data ResultDetails c a b = ResultDetails
  { ResultDetails c a b -> Text
resultDetailsExperimentName :: Text
  , ResultDetails c a b -> Maybe c
resultDetailsExperimentContext :: Maybe c
  , ResultDetails c a b -> ResultControl a
resultDetailsControl :: ResultControl a
  , ResultDetails c a b -> NonEmpty (ResultCandidate b)
resultDetailsCandidates :: NonEmpty (ResultCandidate b)
  , ResultDetails c a b -> [Text]
resultDetailsExecutionOrder :: [Text]
  }

resultDetailsControlValue :: ResultDetails c a b -> a
resultDetailsControlValue :: ResultDetails c a b -> a
resultDetailsControlValue = ResultControl a -> a
forall a. ResultControl a -> a
resultControlValue (ResultControl a -> a)
-> (ResultDetails c a b -> ResultControl a)
-> ResultDetails c a b
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResultDetails c a b -> ResultControl a
forall c a b. ResultDetails c a b -> ResultControl a
resultDetailsControl

resultDetailsCandidate :: ResultDetails c a b -> ResultCandidate b
resultDetailsCandidate :: ResultDetails c a b -> ResultCandidate b
resultDetailsCandidate = NonEmpty (ResultCandidate b) -> ResultCandidate b
forall a. NonEmpty a -> a
NE.head (NonEmpty (ResultCandidate b) -> ResultCandidate b)
-> (ResultDetails c a b -> NonEmpty (ResultCandidate b))
-> ResultDetails c a b
-> ResultCandidate b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResultDetails c a b -> NonEmpty (ResultCandidate b)
forall c a b. ResultDetails c a b -> NonEmpty (ResultCandidate b)
resultDetailsCandidates

data ResultControl a = ResultControl
  { ResultControl a -> Text
resultControlName :: Text
  , ResultControl a -> a
resultControlValue :: a
  , ResultControl a -> Duration
resultControlDuration :: Duration
  }

data ResultCandidate a = ResultCandidate
  { ResultCandidate a -> Text
resultCandidateName :: Text
  , ResultCandidate a -> Either SomeException a
resultCandidateValue :: Either SomeException a
  , ResultCandidate a -> Duration
resultCandidateDuration :: Duration
  }