{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}

module Test.Ngrams.Terms (tests) where

import Data.HashMap.Strict qualified as HashMap
import Data.Map.Strict qualified as Map
import Gargantext.API.Ngrams
import Gargantext.Core (Lang(..))
import Gargantext.Core.Text.Context (TermList)
import Gargantext.Core.Text.Ngrams (NgramsType(NgramsTerms), Ngrams(..))
import Gargantext.Core.Text.Terms (ExtractedNgrams(..))
import Gargantext.Core.Text.Terms.WithList (buildPatterns, buildPatternsWith, extractTermsWithList', termsInText, Pattern(..))
import Gargantext.Database.Action.Flow.Utils (docNgrams, ngramsByDoc)
import Gargantext.Database.Admin.Types.Hyperdata.Document ( HyperdataDocument(..), emptyHyperdataDocument )
import Gargantext.Database.Admin.Types.Node (NodeId(..))
import Gargantext.Database.Schema.Context ( ContextPolyOnlyId(..) )
import Gargantext.Prelude
import Test.Tasty
import Test.Tasty.HUnit


tests :: TestTree
tests = testGroup "Ngrams" [unitTests]

unitTests :: TestTree
unitTests = testGroup "Terms tests"
  [ -- Sorting
    testCase "Build patterns works 01" testBuildPatterns01
  , testCase "Build patterns works 02" testBuildPatterns02

  , testCase "termsInText works 01" testTermsInText01
  , testCase "termsInText works 02" testTermsInText02
  , testCase "termsInText works 03" testTermsInText03
  , testCase "termsInText works 04 (related to issue #221)" testTermsInText04

  , testCase "extractTermsWithList' works 01" testExtractTermsWithList'01

  , testCase "docNgrams works 01" testDocNgrams01
  , testCase "docNgrams works 02" testDocNgrams02

  , testCase "ngramsByDoc works 01" testNgramsByDoc01
  ]

-- | Let's document how the `buildPatternsWith` function works.
testBuildPatterns01 :: Assertion
testBuildPatterns01 = do
  let terms = ["hello world"] :: [NgramsTerm]
  let enPatterns = buildPatternsWith EN terms
  length enPatterns @?= 1
  let Just pat = head enPatterns
  _pat_length pat @?= 2
  _pat_terms pat @?= ["hello", "world"]

-- | Let's document how the `buildPatternsWith` function works.
testBuildPatterns02 :: Assertion
testBuildPatterns02 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let enPatterns = buildPatternsWith EN terms
  length enPatterns @?= 2
  let [pat1, pat2] = enPatterns
  _pat_length pat1 @?= 1
  _pat_terms pat1 @?= ["hello"]
  _pat_length pat2 @?= 1
  _pat_terms pat2 @?= ["world"]

-- | Let's document how the `termsInText` function works.
testTermsInText01 :: Assertion
testTermsInText01 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let enPatterns = buildPatternsWith EN terms
  let tit = termsInText EN enPatterns "Hello, world!"
  length tit @?= 2
  let [tit1, tit2] = tit
  tit1 @?= ("hello", 1)
  tit2 @?= ("world", 1)

-- | Let's document how the `termsInText` function works.
testTermsInText02 :: Assertion
testTermsInText02 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let enPatterns = buildPatternsWith EN terms
  let tit = termsInText EN enPatterns "Hello, world, hello!"
  length tit @?= 2
  let [tit1, tit2] = tit
  tit1 @?= ("hello", 2)
  tit2 @?= ("world", 1)

-- | Let's document how the `termsInText` function works.
testTermsInText03 :: Assertion
testTermsInText03 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let enPatterns = buildPatternsWith EN terms
  let tit = termsInText EN enPatterns "Hello, world, again!"
  length tit @?= 2
  let [tit1, tit2] = tit
  tit1 @?= ("hello", 1)
  tit2 @?= ("world", 1)

-- | Let's document how the `termsInText` function works.
-- https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/221
testTermsInText04 :: Assertion
testTermsInText04 = do
  let terms = ["feuilles de basilic"] :: [NgramsTerm]
  let frPatterns = buildPatternsWith FR terms
  let tit = termsInText FR frPatterns "Infos pratiques Nombre de personnes 1 personne Quantité 1 verre Temps de préparation 5 minutes Degré de difficulté Très facile Coût Abordable Les ingrédients de la recette 4 feuilles de basilic 1 branche de romarin 15 ml de citron jaune 60 ml d'eau gazeuse au mastiqua 90 ml de Bulles de Muscat Jaillance La préparation de la recette Verser dans un verre type long drink le citron jaune, les feuilles de basilic et l'eau gazeuse."
  length tit @?= 1
  let [tit1] = tit
  tit1 @?= ("feuilles de basilic", 2)

testExtractTermsWithList'01 :: Assertion
testExtractTermsWithList'01 = do
  let termList = [(["chat blanc"], [["chat","blanc"]])] :: TermList
  extractTermsWithList' (buildPatterns termList) "Le chat blanc" @?= ["chat blanc"]

testDocNgrams01 :: Assertion
testDocNgrams01 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let hd = emptyHyperdataDocument { _hd_title = Just "hello world"
                                  , _hd_abstract = Nothing }
  let ctx = ContextOnlyId 1 hd
  let dNgrams = docNgrams EN terms ctx
  length dNgrams @?= 2

testDocNgrams02 :: Assertion
testDocNgrams02 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let hd = emptyHyperdataDocument { _hd_title = Just "hello world, kaboom"
                                  , _hd_abstract = Nothing }
  let ctx = ContextOnlyId 1 hd
  let dNgrams = docNgrams EN terms ctx
  length dNgrams @?= 2

testNgramsByDoc01 :: Assertion
testNgramsByDoc01 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let hd1 = emptyHyperdataDocument { _hd_title = Just "hello world, kaboom"
                                   , _hd_abstract = Nothing }
  let ctx1 = ContextOnlyId 1 hd1
  let hd2 = emptyHyperdataDocument { _hd_title = Just "world, boom world"
                                   , _hd_abstract = Nothing }
  let ctx2 = ContextOnlyId 2 hd2

  ngramsByDoc EN NgramsTerms terms ctx1 @?=
    HashMap.fromList
      [ ( SimpleNgrams $ UnsafeNgrams { _ngramsTerms = "hello", _ngramsSize = 1 }
        , Map.singleton NgramsTerms $ Map.singleton (UnsafeMkNodeId 1) (1, 1) )
      , ( SimpleNgrams $ UnsafeNgrams { _ngramsTerms = "world", _ngramsSize = 1 }
        , Map.singleton NgramsTerms $ Map.singleton (UnsafeMkNodeId 1) (1, 1) )
      ]

  ngramsByDoc EN NgramsTerms terms ctx2 @?=
    HashMap.fromList
      [ ( SimpleNgrams $ UnsafeNgrams { _ngramsTerms = "world", _ngramsSize = 1 }
        , Map.singleton NgramsTerms $ Map.singleton (UnsafeMkNodeId 2) (1, 2) )
      ]
