content: module Test.ViewActionSpec where
  
  import Data.Text (Text)
  import GHC.Generics
  import Skeletest
  import Skeletest.Predicate qualified as P
  import Web.Hyperbole (FromJSON, ToJSON)
  import Web.Hyperbole.Data.Encoded
  import Web.Hyperbole.Data.Param
  import Web.Hyperbole.HyperView (ViewAction (..))
  import Web.Hyperbole.HyperView.Event (toActionInput)
  
  
  data Simple = Simple
    deriving (Generic, Eq, Show, Read, ViewAction, ToJSON, FromJSON, ToParam, FromParam)
  
  
  data Product = Product String Int
    deriving (Generic, Show, Eq, ViewAction, Read, ToJSON, FromJSON, ToEncoded, FromEncoded, ToParam, FromParam)
  
  
  data Product' = Product' HasText Int
    deriving (Generic, Show, Eq, ViewAction, Read, ToJSON, FromJSON, ToEncoded, FromEncoded)
  
  
  data Sum
    = SumA
    | SumB Int
    | SubC Text
    | SubD (Maybe Text)
    | SubE Term
    | SubF Simple
    deriving (Generic, Show, Read, Eq, ViewAction)
  
  
  data Compound = Compound Product
    deriving (Generic, Show, Eq, Read, ToJSON, FromEncoded, ToEncoded, FromJSON, ViewAction)
  
  
  data HasText = HasText Text
    deriving (Generic, Show, Eq, Read, ViewAction, ToJSON, FromJSON, FromEncoded, ToEncoded, ToParam, FromParam)
  
  
  newtype Term = Term Text
    deriving newtype (Eq, Show, ToJSON, FromJSON, Read, ToParam, FromParam)
  
  
  spec :: Spec
  spec = withMarkers ["encoded"] $ do
    describe "ViewAction" $ do
      describe "toAction" $ do
        it "simple" $ toAction Simple `shouldBe` Encoded "Simple" []
        it "has text" $ toAction (HasText "hello world") `shouldBe` Encoded "HasText" ["hello world"]
        it "product" $ toAction (Product "hello world" 123) `shouldBe` Encoded "Product" ["hello world", toParam @Int 123]
        it "sum" $ toAction (SumB 123) `shouldBe` Encoded "SumB" [toParam @Int 123]
        it "compound" $ do
          let p = Product "hello world" 123
          toAction (Compound p) `shouldBe` Encoded "Compound" [toParam p]
  
      describe "toActionInput" $ do
        it "Constructor Text" $ do
          toActionInput SubC `shouldBe` Encoded "SubC" []
  
        it "Constructor (Maybe Text)" $ do
          toActionInput (SubD . Just) `shouldBe` Encoded "SubD" []
  
        it "Constructor newtype Term" $ do
          toActionInput (SubE . Term) `shouldBe` Encoded "SubE" []
  
        it "renders data constructors" $ do
          toActionInput SubF `shouldBe` Encoded "SubF" []
  
      describe "parseAction" $ do
        it "simple" $ parseAction (Encoded "Simple" []) `shouldBe` pure Simple
  
        it "parse product" $ do
          parseAction @Product (Encoded "Product" ["woot", toParam @Int 1234]) `shouldSatisfy` P.right P.anything
  
        it "parse product with spaces" $ do
          parseAction @Product (Encoded "Product" ["hello world", toParam @Int 1234]) `shouldSatisfy` P.right P.anything
  
      describe "roundTrip" $ do
        it "simple" $ do
          parseAction (toAction Simple) `shouldBe` pure Simple
        it "has text multiple words" $ do
          let a = HasText "hello world"
          parseAction (toAction a) `shouldBe` pure a
        it "product" $ do
          let a = Product "hello world" 123
          parseAction @Product (toAction a) `shouldBe` pure a
        it "product'" $ do
          let a = Product' (HasText "hello world") 123
          parseAction (toAction a) `shouldBe` pure a
        it "compound" $ do
          let a = Compound (Product "hello world" 123)
          parseAction (toAction a) `shouldBe` pure a
        it "sum" $ do
          let a = SumB 123
          parseAction (toAction a) `shouldBe` pure a
  