{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ViewPatterns #-}

module Text.QQSpec (spec) where

import Test.Hspec
import Text.URI
import Text.URI.QQ qualified as QQ

spec :: Spec
spec = do
  describe "uri" $ do
    it "works as an expression" $ do
      let uriQQ = [QQ.uri|https://markkarpov.com|]
      uri <- mkURI "https://markkarpov.com"
      uriQQ `shouldBe` uri
    it "works as a pattern" $
      mkURI "https://markkarpov.com" >>= \case
        [QQ.uri|https://haskell.org|] -> shouldNotMatch
        [QQ.uri|https://markkarpov.com|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "scheme" $ do
    it "works as an expression" $ do
      let schemeQQ = [QQ.scheme|https|]
      scheme <- mkScheme "https"
      schemeQQ `shouldBe` scheme
    it "works as a pattern" $
      mkScheme "https" >>= \case
        [QQ.scheme|ftp|] -> shouldNotMatch
        [QQ.scheme|https|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "host" $ do
    it "works as an expression" $ do
      let hostQQ = [QQ.host|markkarpov.com|]
      host <- mkHost "markkarpov.com"
      hostQQ `shouldBe` host
    it "works as a pattern" $ do
      mkHost "markkarpov.com" >>= \case
        [QQ.host|haskell.org|] -> shouldNotMatch
        [QQ.host|markkarpov.com|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "username" $ do
    it "works as an expression" $ do
      let usernameQQ = [QQ.username|mark|]
      username <- mkUsername "mark"
      usernameQQ `shouldBe` username
    it "works as a pattern" $ do
      mkUsername "mark" >>= \case
        [QQ.username|chris|] -> shouldNotMatch
        [QQ.username|mark|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "password" $ do
    it "works as an expression" $ do
      let passwordQQ = [QQ.password|secret123|]
      password <- mkPassword "secret123"
      passwordQQ `shouldBe` password
    it "works as a pattern" $ do
      mkPassword "secret123" >>= \case
        [QQ.password|secretXYZ|] -> shouldNotMatch
        [QQ.password|secret123|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "pathPiece" $ do
    it "works as an expression" $ do
      let pathPieceQQ = [QQ.pathPiece|foo|]
      pathPiece <- mkPathPiece "foo"
      pathPieceQQ `shouldBe` pathPiece
    it "works as a pattern" $ do
      mkPathPiece "foo" >>= \case
        [QQ.pathPiece|bar|] -> shouldNotMatch
        [QQ.pathPiece|foo|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "queryKey" $ do
    it "works as an expression" $ do
      let queryKeyQQ = [QQ.queryKey|foo|]
      queryKey <- mkQueryKey "foo"
      queryKeyQQ `shouldBe` queryKey
    it "works as a pattern" $ do
      mkQueryKey "foo" >>= \case
        [QQ.queryKey|xyz|] -> shouldNotMatch
        [QQ.queryKey|foo|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "queryValue" $ do
    it "works as an expression" $ do
      let queryValueQQ = [QQ.queryValue|bar|]
      queryValue <- mkQueryValue "bar"
      queryValueQQ `shouldBe` queryValue
    it "works as a pattern" $ do
      mkQueryValue "bar" >>= \case
        [QQ.queryValue|xyz|] -> shouldNotMatch
        [QQ.queryValue|bar|] -> return ()
        _ -> shouldHaveMatchedAlready

  describe "fragment" $ do
    it "works as an expression" $ do
      let fragmentQQ = [QQ.fragment|frag|]
      fragment <- mkFragment "frag"
      fragmentQQ `shouldBe` fragment
    it "works as a pattern" $ do
      mkFragment "frag" >>= \case
        [QQ.fragment|xyz|] -> shouldNotMatch
        [QQ.fragment|frag|] -> return ()
        _ -> shouldHaveMatchedAlready

shouldNotMatch :: Expectation
shouldNotMatch =
  expectationFailure
    "First case should not have matched, but did"

shouldHaveMatchedAlready :: Expectation
shouldHaveMatchedAlready =
  expectationFailure
    "Second case should have matched, but didn't"
