module Language.Haskell.Format.Utilities (wasReformatted, hunitTest, defaultFormatter) where

import           Language.Haskell.Format
import           Language.Haskell.Format.Definitions
import           Language.Haskell.Source.Enumerator

import           Control.Applicative
import           Control.Monad
import           Data.Monoid
import           Pipes
import qualified Pipes.Prelude                       as P
import           Test.HUnit

type ErrorString = String

data CheckResult = InvalidCheckResult ErrorString
                 | CheckResult HaskellSource Reformatted

hunitTest :: FilePath -> Test
hunitTest filepath = TestLabel filepath $ makeTestCase filepath

makeTestCase :: FilePath -> Test
makeTestCase filepath = TestCase $ do
  formatter <- defaultFormatter
  runEffect $ check formatter filepath >-> assertResults

assertResults :: Consumer CheckResult IO ()
assertResults = forever $ do
  result <- await
  case result of
    (InvalidCheckResult errorString) -> lift $ assertFailure ("Error: " ++ errorString)
    (CheckResult source reformatted) -> when (wasReformatted source reformatted) $ lift $ assertFailure
                                                                                            ("Incorrect formatting: " ++ concatMap
                                                                                                                           show
                                                                                                                           (suggestions
                                                                                                                              reformatted))

check :: Formatter -> FilePath -> Producer CheckResult IO ()
check formatter path = enumeratePath path >->
                       P.mapM readSource >->
                       P.map (checkFormatting formatter)

readSource :: HaskellSourceFilePath -> IO HaskellSource
readSource path = HaskellSource <$> readFile path

checkFormatting :: Formatter -> HaskellSource -> CheckResult
checkFormatting (Formatter format) source =
  case format source of
    Left error        -> InvalidCheckResult error
    Right reformatted -> CheckResult source reformatted

fix :: Formatter -> FilePath -> IO ()
fix = undefined

defaultFormatter :: IO Formatter
defaultFormatter = mconcat <$> (autoSettings >>= formatters)

wasReformatted :: HaskellSource -> Reformatted -> Bool
wasReformatted source reformatted =
  not (null (suggestions reformatted)) || source /= reformattedSource reformatted