module Test.Toml.Parser.Validate
    ( validateSpec
    ) where

import Data.List.NonEmpty (NonEmpty (..))
import Hedgehog (evalEither, forAll)
import Test.Hspec (Arg, Expectation, Spec, SpecWith, describe, it, shouldBe)
import Test.Hspec.Hedgehog (hedgehog)
import Text.Megaparsec (parse)

import Test.Toml.Gen (genToml)
import Toml.Parser.Item (Table (..), TomlItem (..), tomlP)
import Toml.Parser.Validate (ValidationError (..), validateItems)
import Toml.Type.AnyValue (AnyValue (..))
import Toml.Type.Key (Key)
import Toml.Type.Printer (pretty)
import Toml.Type.Value (Value (..))


validateSpec :: Spec
validateSpec = describe "Parser Validation tests" $ do
  -- property success
    validationProperty
    -- failure
    validationFail
        [keyVal "key", keyVal "key"]
        (DuplicateKey "key")
    validationFail
        [TableName "table", TableName "table"]
        (DuplicateTable "table")
    validationFail
        [keyVal "keyAndTable", TableName "keyAndTable"]
        (SameNameKeyTable "keyAndTable")
    validationFail
        [TableName "tableArray", TableArrayName "tableArray"]
        (SameNameTableArray "tableArray")
    validationFail
        [TableArrayName "tableArray", TableName "tableArray"]
        (SameNameTableArray "tableArray")
    validationFail
        [inlineTable "inline", TableName "inline"]
        (DuplicateTable "inline")
    validationFail
        [keyVal "inline", inlineTable "inline"]
        (SameNameKeyTable "inline")
    validationFail
        [inlineTableArray, TableName "inlinearray"]
        (SameNameTableArray "inlinearray")
    validationFail
        [inlineTableArray, inlineTable "inlinearray"]
        (SameNameTableArray "inlinearray")
    validationFail
        [inlineTable "inlinearray", inlineTableArray]
        (SameNameTableArray "inlinearray")

  where
    keyVal :: Key -> TomlItem
    keyVal k = KeyVal k (AnyValue $ Bool True)

    inlineTable :: Key -> TomlItem
    inlineTable k = InlineTable k table

    inlineTableArray :: TomlItem
    inlineTableArray = InlineTableArray "inlinearray" (table :| [])

    table :: Table
    table = Table []

validationProperty :: SpecWith (Arg Expectation)
validationProperty = it "Property: validates any generated TOML" $ hedgehog $ do
    toml <- forAll genToml
    let tomlText = pretty toml
    tomlItems <- evalEither $ parse tomlP "" tomlText
    _ <- evalEither (validateItems tomlItems)
    pure ()

validationFail :: [TomlItem] -> ValidationError -> SpecWith (Arg Expectation)
validationFail tomlItems validationError = it ("fail on " ++ show validationError) $
    validateItems tomlItems `shouldBe` Left validationError