{-# 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.Types ( NgramsTerm )
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.Hspec
import Test.HUnit


tests :: Spec
tests = describe "Ngrams" unitTests

unitTests :: Spec
unitTests = describe "Terms tests" $ do
  -- Sorting
  it "Build patterns works 01" testBuildPatterns01
  it "Build patterns works 02" testBuildPatterns02
  it "termsInText works 01" testTermsInText01
  it "termsInText works 02" testTermsInText02
  it "termsInText works 03" testTermsInText03
  it "termsInText works 04 (related to issue #221)" testTermsInText04
  it "extractTermsWithList' works 01" testExtractTermsWithList'01
  it "extractTermsWithList' works 02 (#471)" testExtractTermsWithList'02
  it "docNgrams works 01" testDocNgrams01
  it "docNgrams works 02" testDocNgrams02
  it "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"]

-- #471
testExtractTermsWithList'02 :: Assertion
testExtractTermsWithList'02 = do
  let termList = [(["patients"], []), (["patients", "with"], [])] :: TermList
  extractTermsWithList' (buildPatterns termList) "patients with problems" @?= ["patients", "patientswith"]

testDocNgrams01 :: Assertion
testDocNgrams01 = do
  let terms = ["hello", "world"] :: [NgramsTerm]
  let hd = emptyHyperdataDocument { _hd_title = Just "hello world"
                                  , _hd_abstract = Nothing }
  let ctx = ContextOnlyId { _context_oid_id = 1, _context_oid_hyperdata = 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 { _context_oid_id = 1, _context_oid_hyperdata = 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 { _context_oid_id = 1, _context_oid_hyperdata = hd1 }
  let hd2 = emptyHyperdataDocument { _hd_title = Just "world, boom world"
                                   , _hd_abstract = Nothing }
  let ctx2 = ContextOnlyId { _context_oid_id = 2, _context_oid_hyperdata = 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) )
      ]
