{-|
Module      : Gargantext.Database.Admin.Types.Hyperdata.Document
Description :
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX

-}

{-# LANGUAGE TemplateHaskell            #-}

module Gargantext.Database.Admin.Types.Hyperdata.Document where

import Codec.Serialise.Class hiding (decode)
import Gargantext.Core.Text (HasText(..))
import Gargantext.Core.Utils.DateUtils (UTCTimeR(..))
import Gargantext.Core.Utils.Prefix (unCapitalize, dropPrefix)
import Gargantext.Database.Admin.Types.Hyperdata.Prelude
import Gargantext.Defaults qualified as Def
import Gargantext.Prelude hiding (ByteString)

------------------------------------------------------------------------
data HyperdataDocument = HyperdataDocument { _hd_bdd                :: !(Maybe Text)
                                           , _hd_doi                :: !(Maybe Text)
                                           , _hd_url                :: !(Maybe Text)
                                           , _hd_page               :: !(Maybe Int)
                                           , _hd_title              :: !(Maybe Text)
                                           , _hd_authors            :: !(Maybe Text)
                                           , _hd_institutes         :: !(Maybe Text)
                                           , _hd_source             :: !(Maybe Text)
                                           , _hd_abstract           :: !(Maybe Text)
                                           , _hd_publication_date   :: !(Maybe Text)
                                           , _hd_publication_year   :: !(Maybe Int)
                                           , _hd_publication_month  :: !(Maybe Int)
                                           , _hd_publication_day    :: !(Maybe Int)
                                           , _hd_publication_hour   :: !(Maybe Int)
                                           , _hd_publication_minute :: !(Maybe Int)
                                           , _hd_publication_second :: !(Maybe Int)
                                           , _hd_language_iso2      :: !(Maybe Text)
                                           , _hd_institutes_tree    :: !(Maybe (Map Text [Text]))
                                           }
  deriving (Show, Generic)

instance NFData HyperdataDocument
instance Serialise HyperdataDocument

instance HasText HyperdataDocument
  where
    hasText h = catMaybes [ _hd_title    h
                          , _hd_abstract h
                          ]

emptyHyperdataDocument :: HyperdataDocument
emptyHyperdataDocument = HyperdataDocument { _hd_bdd = Nothing
                                           , _hd_doi = Nothing
                                           , _hd_url = Nothing
                                           , _hd_page = Nothing
                                           , _hd_title = Nothing
                                           , _hd_authors = Nothing
                                           , _hd_institutes = Nothing
                                           , _hd_source = Nothing
                                           , _hd_abstract = Nothing
                                           , _hd_publication_date = Nothing
                                           , _hd_publication_year = Nothing
                                           , _hd_publication_month = Nothing
                                           , _hd_publication_day = Nothing
                                           , _hd_publication_hour = Nothing
                                           , _hd_publication_minute = Nothing
                                           , _hd_publication_second = Nothing
                                           , _hd_language_iso2 = Nothing
                                           , _hd_institutes_tree = Nothing }

defaultHyperdataDocument :: HyperdataDocument
defaultHyperdataDocument = case decode docExample of
  Just hp -> hp
  Nothing -> emptyHyperdataDocument

  where
    docExample :: ByteString
    docExample = "{\"doi\":\"sdfds\",\"publication_day\":6,\"language_iso2\":\"en\",\"publication_minute\":0,\"publication_month\":7,\"language_iso3\":\"eng\",\"publication_second\":0,\"authors\":\"Nils Hovdenak, Kjell Haram\",\"publication_year\":2012,\"publication_date\":\"2012-07-06 00:00:00+00:00\",\"language_name\":\"English\",\"realdate_full_\":\"2012 01 12\",\"source\":\"European journal of obstetrics, gynecology, and reproductive biology\",\"abstract\":\"The literature was searched for publications on minerals and vitamins during pregnancy and the possible influence of supplements on pregnancy outcome.\",\"title\":\"Influence of mineral and vitamin supplements on pregnancy outcome.\",\"publication_hour\":0}"


unwrapHyperdataDateTime :: HyperdataDocument -> UTCTimeR
unwrapHyperdataDateTime HyperdataDocument { .. } =
  UTCTimeR { year = fromMaybe (fromIntegral Def.year) _hd_publication_year
           , month = fromMaybe Def.month _hd_publication_month
           , day = fromMaybe Def.day _hd_publication_day
           , hour = fromMaybe Def.hour _hd_publication_hour
           , minute = fromMaybe Def.minute _hd_publication_minute
           , sec = fromMaybe Def.second _hd_publication_second }

------------------------------------------------------------------------
-- | Legacy Garg V3 compatibility (to be removed one year after release)
data StatusV3  = StatusV3 { statusV3_error  :: !(Maybe Text)
                          , statusV3_action :: !(Maybe Text)
                      } deriving (Show, Generic)

------------------------------------------------------------------------
data HyperdataDocumentV3 = HyperdataDocumentV3 { _hdv3_publication_day    :: !(Maybe Int)
                                               , _hdv3_language_iso2      :: !(Maybe Text)
                                               , _hdv3_publication_second :: !(Maybe Int)
                                               , _hdv3_publication_minute :: !(Maybe Int)
                                               , _hdv3_publication_month  :: !(Maybe Int)
                                               , _hdv3_publication_hour   :: !(Maybe Int)
                                               , _hdv3_error              :: !(Maybe Text)
                                               , _hdv3_language_iso3      :: !(Maybe Text)
                                               , _hdv3_authors            :: !(Maybe Text)
                                               , _hdv3_publication_year   :: !(Maybe Int)
                                               , _hdv3_publication_date   :: !(Maybe Text)
                                               , _hdv3_language_name      :: !(Maybe Text)
                                               , _hdv3_statuses           :: !(Maybe [StatusV3])
                                               , _hdv3_realdate_full_     :: !(Maybe Text)
                                               , _hdv3_source             :: !(Maybe Text)
                                               , _hdv3_abstract           :: !(Maybe Text)
                                               , _hdv3_title              :: !(Maybe Text)
                                               } deriving (Show, Generic)


------------------------------------------------------------------------
-- | Instances for Analysis
------------------------------------------------------------------------
class ToHyperdataDocument a where
  toHyperdataDocument :: a -> HyperdataDocument

instance ToHyperdataDocument HyperdataDocument
  where
    toHyperdataDocument = identity

------------------------------------------------------------------------
instance Eq HyperdataDocument where
  (==) h1 h2 = _hd_title h1 == _hd_title h2
            && _hd_abstract h1 == _hd_abstract h2

------------------------------------------------------------------------
instance Ord HyperdataDocument where
  compare h1 h2 = compare (_hd_publication_date h1) (_hd_publication_date h2)
------------------------------------------------------------------------
instance Arbitrary HyperdataDocument where
    arbitrary = elements arbitraryHyperdataDocuments

arbitraryHyperdataDocuments :: [HyperdataDocument]
arbitraryHyperdataDocuments =
  map toHyperdataDocument' ([ ("AI is big but less than crypto", "Troll System journal")
                            , ("Crypto is big but less than AI", "System Troll review" )
                            , ("Science is magic"              , "Closed Source review")
                            , ("Open science for all"          , "No Time"             )
                            , ("Closed science for me"         , "No Space"            )
                            ] :: [(Text, Text)])
  where
    toHyperdataDocument' (t1,t2) =
      HyperdataDocument Nothing Nothing Nothing Nothing (Just t1)
                      Nothing Nothing (Just t2) Nothing Nothing Nothing Nothing Nothing
                      Nothing Nothing Nothing   Nothing Nothing



------------------------------------------------------------------------
-- | Common Instances of Hyperdata
------------------------------------------------------------------------
instance Hyperdata HyperdataDocument
instance Hyperdata HyperdataDocumentV3
------------------------------------------------------------------------
-- $(deriveJSON (unPrefix "_hd_") ''HyperdataDocument)
instance ToSchema HyperdataDocument where
  declareNamedSchema proxy =
    genericDeclareNamedSchema (unPrefixSwagger "_hd_") proxy
    & mapped.schema.description ?~ "Document Hyperdata"
    & mapped.schema.example ?~ toJSON defaultHyperdataDocument

{-
-- | For now HyperdataDocumentV3 is not exposed with the API
instance ToSchema HyperdataDocumentV3 where
  declareNamedSchema proxy =
    genericDeclareNamedSchema (unPrefixSwagger "hyperdataDocumentV3_") proxy
    & mapped.schema.description ?~ "Document Hyperdata for Garg V3"
    & mapped.schema.example ?~ toJSON defaultHyperdataDocumentV3
-}

--
-- JSON instances
--

instance FromJSON HyperdataDocument
  where
    parseJSON = genericParseJSON
            ( defaultOptions { sumEncoding = ObjectWithSingleField
                            , fieldLabelModifier = unCapitalize . dropPrefix "_hd_"
                            , omitNothingFields = True
                            }
            )

instance ToJSON HyperdataDocument
  where
    toJSON = genericToJSON
           ( defaultOptions { sumEncoding = ObjectWithSingleField
                            , fieldLabelModifier = unCapitalize . dropPrefix "_hd_"
                            , omitNothingFields = True
                            }
           )



$(deriveJSON (unPrefix "statusV3_") ''StatusV3)
$(deriveJSON (unPrefix "_hdv3_") ''HyperdataDocumentV3)

--
-- FromField/ToField instances
--

instance FromField HyperdataDocument
  where
    fromField = fromField'

instance FromField HyperdataDocumentV3
  where
    fromField = fromField'

instance ToField HyperdataDocument where
  toField = toJSONField

instance ToField HyperdataDocumentV3 where
  toField = toJSONField

instance DefaultFromField SqlJsonb HyperdataDocument
  where
    defaultFromField = fromPGSFromField

instance DefaultFromField SqlJsonb HyperdataDocumentV3
  where
    defaultFromField = fromPGSFromField

--
-- Lenses
--
$(makeLenses ''HyperdataDocument)
makePrisms ''HyperdataDocument
$(makeLenses ''HyperdataDocumentV3)
