{-# OPTIONS_GHC -fno-warn-orphans #-}

{- |
Module      :  Servant.RawM.Internal.Docs

Copyright   :  Dennis Gosnell 2017
License     :  BSD3

Maintainer  :  Dennis Gosnell (cdep.illabout@gmail.com)
Stability   :  experimental
Portability :  unknown

This module exports a 'HasDocs' instance for 'RawM'.
-}

module Servant.RawM.Internal.Docs where

-- import Data.Proxy (Proxy(Proxy))
-- import Data.ByteString.Lazy (ByteString)
-- import Data.Function ((&))
-- import Data.Monoid ((<>))
-- import Data.Text (Text)
-- import Network.HTTP.Media (MediaType)
-- import Servant.API (Verb, (:>))
-- import Servant.API.ContentTypes (AllMimeRender(allMimeRender))
-- import Servant.Docs
--        (Action, API, DocOptions, Endpoint, HasDocs(docsFor),
--         ToSample(toSamples))
-- import Servant.Docs.Internal (apiEndpoints, respBody, response)

-- import Servant.RawM.Internal.Envelope
--        (Envelope, toErrEnvelope, toSuccEnvelope)
-- import Servant.RawM.Internal.Prism ((<>~))
-- import Servant.RawM.Internal.Servant.API
--        (NoThrow, Throws, Throwing)
-- import Servant.RawM.Internal.Util (Snoc)

-- -- TODO: Make sure to also account for when headers are being used.

-- -- | Change a 'Throws' into 'Throwing'.
-- instance (HasDocs (Throwing '[e] :> api)) => HasDocs (Throws e :> api) where
--   docsFor
--     :: Proxy (Throws e :> api)
--     -> (Endpoint, Action)
--     -> DocOptions
--     -> API
--   docsFor Proxy = docsFor (Proxy :: Proxy (Throwing '[e] :> api))

-- -- | When @'Throwing' es@ comes before a 'Verb', generate the documentation for
-- -- the same 'Verb', but returning an @'Envelope' es@.  Also add documentation
-- -- for the potential @es@.
-- instance
--        ( CreateRespBodiesFor es ctypes
--        , HasDocs (Verb method status ctypes (Envelope es a))
--        )
--     => HasDocs (Throwing es :> Verb method status ctypes a) where
--   docsFor
--     :: Proxy (Throwing es :> Verb method status ctypes a)
--     -> (Endpoint, Action)
--     -> DocOptions
--     -> API
--   docsFor Proxy (endpoint, action) docOpts =
--     let api =
--           docsFor
--             (Proxy :: Proxy (Verb method status ctypes (Envelope es a)))
--             (endpoint, action)
--             docOpts
--     in api & apiEndpoints . traverse . response . respBody <>~
--         createRespBodiesFor (Proxy :: Proxy es) (Proxy :: Proxy ctypes)

-- -- | When 'NoThrow' comes before a 'Verb', generate the documentation for
-- -- the same 'Verb', but returning an @'Envelope' \'[]@.
-- instance (HasDocs (Verb method status ctypes (Envelope '[] a)))
--     => HasDocs (NoThrow :> Verb method status ctypes a) where
--   docsFor
--     :: Proxy (NoThrow :> Verb method status ctypes a)
--     -> (Endpoint, Action)
--     -> DocOptions
--     -> API
--   docsFor Proxy (endpoint, action) docOpts =
--     docsFor
--       (Proxy :: Proxy (Verb method status ctypes (Envelope '[] a)))
--       (endpoint, action)
--       docOpts

-- -- | Create samples for a given @list@ of types, under given @ctypes@.
-- --
-- -- Additional instances of this class should not need to be created.
-- class CreateRespBodiesFor list ctypes where
--   createRespBodiesFor
--     :: Proxy list
--     -> Proxy ctypes
--     -> [(Text, MediaType, ByteString)]

-- -- | An empty list of types has no samples.
-- instance CreateRespBodiesFor '[] ctypes where
--   createRespBodiesFor
--     :: Proxy '[]
--     -> Proxy ctypes
--     -> [(Text, MediaType, ByteString)]
--   createRespBodiesFor Proxy Proxy = []

-- -- | Create a response body for each of the error types.
-- instance
--        ( AllMimeRender ctypes (Envelope '[e] ())
--        , CreateRespBodiesFor es ctypes
--        , ToSample e
--        )
--     => CreateRespBodiesFor (e ': es) ctypes where
--   createRespBodiesFor
--     :: Proxy (e ': es)
--     -> Proxy ctypes
--     -> [(Text, MediaType, ByteString)]
--   createRespBodiesFor Proxy ctypes =
--     createRespBodyFor (Proxy :: Proxy e) ctypes <>
--     createRespBodiesFor (Proxy :: Proxy es) ctypes

-- -- | Create a sample for a given @e@ under given @ctypes@.
-- createRespBodyFor
--   :: forall e ctypes.
--      (AllMimeRender ctypes (Envelope '[e] ()), ToSample e)
--   => Proxy e -> Proxy ctypes -> [(Text, MediaType, ByteString)]
-- createRespBodyFor Proxy ctypes = concatMap enc samples
--     where
--       samples :: [(Text, Envelope '[e] ())]
--       samples = fmap toErrEnvelope <$> toSamples (Proxy :: Proxy e)

--       enc :: (Text, Envelope '[e] ()) -> [(Text, MediaType, ByteString)]
--       enc (t, s) = uncurry (t,,) <$> allMimeRender ctypes s

-- -- | When a @'Throws' e@ comes immediately after a @'Throwing' es@, 'Snoc' the
-- -- @e@ onto the @es@.
-- instance (HasDocs (Throwing (Snoc es e) :> api)) =>
--     HasDocs (Throwing es :> Throws e :> api) where
--   docsFor
--     :: Proxy (Throwing es :> Throws e :> api)
--     -> (Endpoint, Action)
--     -> DocOptions
--     -> API
--   docsFor Proxy =
--     docsFor (Proxy :: Proxy (Throwing (Snoc es e) :> api))

-- -- | We can generate a sample of an @'Envelope' es a@ as long as there is a way
-- -- to generate a sample of the @a@.
-- --
-- -- This doesn't need to worry about generating a sample of @es@, because that is
-- -- taken care of in the 'HasDocs' instance for @'Throwing' es@.
-- instance ToSample a => ToSample (Envelope es a) where
--   toSamples :: Proxy (Envelope es a) -> [(Text, Envelope es a)]
--   toSamples Proxy = fmap toSuccEnvelope <$> toSamples (Proxy :: Proxy a)