{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeOperators         #-}

module Servant.PY.Python where

import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy  as LB
import           Data.Data
import           Data.Monoid           ((<>))
import           Data.Text             (Text)
import qualified Data.Text             as T
import           GHC.TypeLits
import           Servant.Foreign

data Python

getFieldsForInstance :: forall a. Data a => a -> [Text]
getFieldsForInstance = map T.pack . mconcat . map constrFields . getConstr
  where getConstr = dataTypeConstrs . dataTypeOf

getFieldTypesForType :: forall a. Typeable a => a -> [Text]
getFieldTypesForType = init . T.splitOn " -> " . T.pack . show . typeOf

recordToDict :: forall a b. (Data a, Typeable b) => a -> b -> T.Text
recordToDict fieldsInstance fieldsType = "{" <> T.intercalate ", " (map printPair fieldPairs) <> "}"
  where printPair (c, d) = "\"" <> c <> "\": " <> d
        fieldPairs = zip fieldNames fieldTypes
        fieldNames = getFieldsForInstance fieldsInstance
        fieldTypes = getFieldTypesForType fieldsType

instance HasForeignType Python Text NoContent where
  typeFor _ _ _ = "None"

instance HasForeignType Python Text Int where
  typeFor _ _ _ = "int"

instance HasForeignType Python Text Bool where
  typeFor _ _ _ = "bool"

instance HasForeignType Python Text String where
  typeFor _ _ _ = "str"

instance HasForeignType Python Text Text where
  typeFor _ _ _ = "str"

instance HasForeignType Python Text LB.ByteString where
  typeFor _ _ _ = "str"

instance HasForeignType Python Text B.ByteString where
  typeFor _ _ _ = "str"

instance HasForeignType Python Text JSON where
  typeFor _ _ _ = "dict"

instance HasForeignType Python T.Text (a :: Symbol) where
  typeFor _ _ _ = "str"

instance HasForeignType Python Text a => HasForeignType Python Text (Header a) where
  typeFor lang ftype _ = "dict" <> typeFor lang ftype (Proxy :: Proxy a)

instance HasForeignType Python Text a => HasForeignType Python Text (Headers '[Header a b] c) where
  typeFor lang ftype _ = "dict" <> typeFor lang ftype (Proxy :: Proxy a)

instance HasForeignType Python Text a => HasForeignType Python Text [Header a b] where
  typeFor lang ftype _ = "[dict of " <> typeFor lang ftype (Proxy :: Proxy a) <> "]"

instance HasForeignType Python Text a => HasForeignType Python Text (Headers a) where
  typeFor lang ftype _ = "dict" <> typeFor lang ftype (Proxy :: Proxy a)

instance HasForeignType Python Text a => HasForeignType Python Text (Maybe a) where
  typeFor lang ftype _ = "Optional" <> typeFor lang ftype (Proxy :: Proxy a)

instance HasForeignType Python Text a => HasForeignType Python Text [a] where
   typeFor lang ftype _ = "list of " <> typeFor lang ftype (Proxy :: Proxy a)