{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}

module Test.Pos.Chain.Ssc.Json
       ( tests
       ) where
import           Universum

import qualified Cardano.Crypto.Wallet as CC
import           Data.Aeson (eitherDecode)
import qualified Data.ByteString.Lazy as LB
import           Hedgehog (Property)
import qualified Hedgehog as H
import           Hedgehog.Internal.Property (assert, failWith, withTests)

import           Pos.Chain.Security (AttackTarget (..))
import           Pos.Crypto.Hashing (abstractHash)
import           Pos.Crypto.Signing (PublicKey (..))

import           Test.Pos.Chain.Ssc.Gen (genAttackTarget)
import           Test.Pos.Util.Golden (discoverGolden, goldenTestJSONPretty,
                     goldenValueEquiv)
import           Test.Pos.Util.Tripping (discoverRoundTrip,
                     roundTripsAesonYamlShow)

-------------------------------------------------------------------------------
-- AttackTarget
-------------------------------------------------------------------------------
golden_AttackTarget_NetworkAddressTarget :: Property
golden_AttackTarget_NetworkAddressTarget =
    goldenTestJSONPretty exampleAttackTarget_NetworkAddressTarget
        "test/golden/json/AttackTarget_NetworkAddressTarget"

exampleAttackTarget_NetworkAddressTarget :: AttackTarget
exampleAttackTarget_NetworkAddressTarget = NetworkAddressTarget ("ggv", 32313)

{-# ANN module ("HLint: ignore Reduce duplication" :: Text) #-}

golden_prettyEquivalence_AttackTarget_NetworkAddressTarget :: Property
golden_prettyEquivalence_AttackTarget_NetworkAddressTarget =
    withFrozenCallStack $ do
        withTests 1 . H.property $ do
            prettyJ <- liftIO $ LB.readFile pFile
            oldJ <- liftIO $ LB.readFile oFile
            let equivTest = goldenValueEquiv
                                (eitherDecode prettyJ :: Either String AttackTarget)
                                (eitherDecode oldJ :: Either String AttackTarget)
            case equivTest of
                Left err    -> failWith Nothing $ "could not decode: " <> show err
                Right bool' -> assert bool'
  where
    pFile = "test/golden/json/AttackTarget_NetworkAddressTarget"
    oFile = "test/golden/oldJson/AttackTarget_NetworkAddressTarget"

golden_AttackTarget_PubKeyAddressTarget :: Property
golden_AttackTarget_PubKeyAddressTarget =
    goldenTestJSONPretty exampleAttackTarget_PubKeyAddressTarget
        "test/golden/json/AttackTarget_PubKeyAddressTarget"

exampleAttackTarget_PubKeyAddressTarget :: AttackTarget
exampleAttackTarget_PubKeyAddressTarget =
    PubKeyAddressTarget
        $ abstractHash (PublicKey (CC.XPub {CC.xpubPublicKey = pubKey1
          , CC.xpubChaincode = CC.ChainCode "Test"}))
  where
    pubKey1 = "\145\&3\131kUF\226\131\253M\174\157;w>\156k"

golden_prettyEquivalence_AttackTarget_PubKeyAddressTarget :: Property
golden_prettyEquivalence_AttackTarget_PubKeyAddressTarget =
    withFrozenCallStack $ do
        withTests 1 . H.property $ do
            prettyJ <- liftIO $ LB.readFile pFile
            oldJ <- liftIO $ LB.readFile oFile
            let equivTest = goldenValueEquiv
                                (eitherDecode prettyJ :: Either String AttackTarget)
                                (eitherDecode oldJ :: Either String AttackTarget)
            case equivTest of
                Left err    -> failWith Nothing $ "could not decode: " <> show err
                Right bool' -> assert bool'
  where
    pFile = "test/golden/json/AttackTarget_PubKeyAddressTarget"
    oFile = "test/golden/oldJson/AttackTarget_PubKeyAddressTarget"

roundTripAttackTarget :: Property
roundTripAttackTarget =
    roundTripsAesonYamlShow 1000 genAttackTarget

-------------------------------------------------------------------------------
-- Main test export
-------------------------------------------------------------------------------

tests :: IO Bool
tests = (&&) <$> H.checkSequential $$discoverGolden
             <*> H.checkParallel $$discoverRoundTrip
