{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveGeneric #-}
module Gargantext.API.Routes.Named.Search (
  -- * Routes types
    SearchAPI(..)

  -- * API types (appears in the routes)
  , SearchType(..)
  , SearchQuery(..)
  , SearchResult(..)
  , SearchResultTypes(..)
  ) where


import Data.Aeson
import Data.Swagger
import Data.Text (Text)
import GHC.Generics
import Gargantext.Core.Text.Corpus.Query (RawQuery (..))
import Gargantext.Core.Types.Query (Limit, Offset)
import Gargantext.Core.Types.Search
import Gargantext.Core.Utils.Prefix (unPrefixSwagger)
import Gargantext.Database.Query.Facet
import Prelude
import Servant
import Test.QuickCheck


-- TODO-ACCESS: CanSearch? or is it part of CanGetNode
-- TODO-EVENTS: No event, this is a read-only query.
data SearchAPI results mode = SearchAPI
  { searchEp :: mode :- Summary "Search endpoint"
                     :> ReqBody '[JSON] SearchQuery
                     :> QueryParam "offset" Offset
                     :> QueryParam "limit"  Limit
                     :> QueryParam "order"  OrderBy
                     :> Post '[JSON] results
  } deriving Generic


data SearchType = SearchDoc | SearchContact | SearchDocWithNgrams
  deriving Generic


data SearchQuery = SearchQuery
  { query    :: !RawQuery
  , expected :: !SearchType
  } deriving Generic


newtype SearchResult =
  SearchResult { result :: SearchResultTypes }
    deriving Generic


data SearchResultTypes =
    SearchResultDoc { docs     :: ![Row] }
  | SearchResultContact  { contacts :: ![Row] }
  | SearchNoResult      { message  :: !Text }
  deriving Generic


--
-- instances
--

instance FromJSON SearchResult where
  parseJSON = genericParseJSON defaultOptions

instance ToJSON SearchResult where
  toJSON = genericToJSON defaultOptions

instance ToSchema SearchResult

instance Arbitrary SearchResult where
  arbitrary = SearchResult <$> arbitrary

instance FromJSON SearchResultTypes where
  parseJSON = genericParseJSON (defaultOptions { sumEncoding = defaultTaggedObject })

instance ToJSON SearchResultTypes where
  toJSON = genericToJSON (defaultOptions { sumEncoding = defaultTaggedObject })

instance Arbitrary SearchResultTypes where
  arbitrary = do
    srd <- SearchResultDoc     <$> arbitrary
    src <- SearchResultContact <$> arbitrary
    srn <- pure $ SearchNoResult "No result because.."
    elements [srd, src, srn]

instance ToSchema SearchResultTypes where
  declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "")

instance FromJSON SearchQuery where
  parseJSON = genericParseJSON defaultOptions

instance ToJSON SearchQuery where
  toJSON = genericToJSON defaultOptions

instance ToSchema SearchQuery

instance Arbitrary SearchQuery where
  arbitrary = elements [SearchQuery (RawQuery "electrodes") SearchDoc]

instance FromJSON SearchType where
  parseJSON = genericParseJSON (defaultOptions { sumEncoding = ObjectWithSingleField })

instance ToJSON SearchType where
  toJSON = genericToJSON (defaultOptions { sumEncoding = ObjectWithSingleField })

instance ToSchema SearchType

instance Arbitrary SearchType where
  arbitrary = elements [SearchDoc, SearchContact]
