module Lib where

import Text.Regex.PCRE.Heavy
import Data.ByteString (ByteString)
import Data.String.Interpolate
import System.Exit

data Threshold = Threshold
  { thresholdName :: String
  , thresholdRegex :: ByteString
  , thresholdValue :: Double
  } deriving (Read, Show)

type Coverage = Double
type ThresholdEvaluationResult = (Threshold, Coverage, Bool)

extractCoverage :: String -> ByteString -> Double
extractCoverage src regexStr =
  case compileM regexStr [] of
    Left e ->
      error e
    Right regex ->
      case scan regex src of
        (_, coverage:_):_ ->
          read coverage
        _ ->
          0

evaluate :: String -> [Threshold] -> [ThresholdEvaluationResult]
evaluate src thresholds = do
  threshold <- thresholds
  let 
    coverage =
      extractCoverage src (thresholdRegex threshold)
    isPass =
      coverage >= thresholdValue threshold
  return (threshold, coverage, isPass)

reportThreshold :: ThresholdEvaluationResult -> String
reportThreshold (Threshold tName _ tValue, coverage, isPass) =
  let
    remark = if isPass then "✓" else "·"
    sign = if isPass then "≥" else "<"
  in
    [i|#{remark} #{tName}: #{coverage}% (#{sign} #{tValue}%)|]

evaluateAndReport :: String -> [Threshold] -> (String, Bool)
evaluateAndReport src thresholds =
  let
    evalResults = evaluate src thresholds
    isAllThresholdPass = all (\(_, _, isPass) -> isPass) evalResults
    reportSummary =
      if isAllThresholdPass
        then "Code coverage threshold check: PASS"
        else "Code coverage threshold check: FAIL"
    report = unlines $ reportSummary : map reportThreshold evalResults
  in
    (report, isAllThresholdPass)

evaluateAndReport' :: IO ()
evaluateAndReport' = do
  thresholds <- readFile ".hpc-threshold" >>= return . read
  src <- getContents
  let (report, isPass) = evaluateAndReport src thresholds
  putStrLn report
  if isPass
    then exitWith ExitSuccess
    else exitWith $ ExitFailure 1