{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}

module Gargantext.API.Routes.Named.Share (
  -- * Routes types
    ShareNode(..)
  , UnshareNode(..)
  , ShareURL(..)
  , ShareLink(..)
  , renderShareLink

  -- * API types (which appears in the routes)
  , ShareNodeParams(..)
  ) where

import Data.Aeson (withText)
import Data.Swagger (ToSchema, declareNamedSchema)
import Data.Text qualified as T
import Gargantext.API.Node.Share.Types ( ShareNodeParams (..) )
import Gargantext.Database.Admin.Types.Node
import Gargantext.Prelude
import Network.URI (parseURI)
import Prelude (fail)
import Servant

-- | A shareable link.
-- N.B. We don't use a 'BareUrl' internally, because parsing something like
-- 'http://localhost/#/share/NodeCorpus/16'
-- would fail because '#/share/NodeCorpus/16' by the RFC3968 spec is considered
-- an uriFragment, but BaseUrl cannot handle that.
newtype ShareLink = ShareLink { getShareLink :: URI }
  deriving (Show, Eq, Ord, Generic)

instance NFData ShareLink where

renderShareLink :: ShareLink -> T.Text
renderShareLink = T.pack . show . getShareLink

instance ToJSON ShareLink where
  toJSON = toJSON . renderShareLink

instance FromJSON ShareLink where
  parseJSON = withText "ShareLink" $ \txt ->
    let urlStr = T.unpack txt
    in case parseURI urlStr of
          Nothing -> fail $ "Invalid URL: " <> urlStr
          Just u  -> pure $ ShareLink u

instance ToSchema ShareLink where
  declareNamedSchema _ = declareNamedSchema (Proxy @T.Text)

newtype ShareURL mode = ShareURL
  { shareUrlEp :: mode :- Summary "Fetch URL for sharing a node"
                       :> QueryParam "type" NodeType
                       :> QueryParam "id" NodeId
                       :> Get '[JSON] ShareLink
  } deriving Generic


newtype ShareNode mode = ShareNode
  { shareNodeEp :: mode :- Summary " Share Node with username"
                        :> ReqBody '[JSON] ShareNodeParams
                        :> Post    '[JSON] Int
  } deriving Generic


newtype UnshareNode mode = UnshareNode
  { unshareEp :: mode :- Summary " Unshare a Node" :> Capture "node_id" NodeId :> Put '[JSON] Int
  } deriving Generic