{-# LANGUAGE TemplateHaskell #-}
module Network.Yandex.Translate.Types (
    -- types
    APIKey,
    Language,
    LanguagesDescr,
    Direction(..),
    YandexApiT,
    ApiInfo,
    YandexApiConfig(..),
    TranslateParams(..),
    -- lens
    apikey,
    httpOptions,
    format,
    options,
    _config,
    _session,
    -- funcs
    formatDirection,
    directionAsText,
    configureApi,
    runYandexApiT,
    runYandexApi,
    runYandexApiSession
) where
import Prelude hiding (drop)
import Data.Default.Class
import Control.Monad.Trans.Reader
import Control.Lens
import Data.Aeson
import Data.Monoid
import Data.HashMap.Strict
import Data.Text
import Control.Monad.IO.Class
import Network.Wreq hiding (options)
import Network.Wreq.Session (Session, withAPISession)


type APIKey = Text
type Language = Text
type LanguagesDescr = HashMap Text Text
newtype Direction = Direction (Language, Language)
    deriving(Eq)

type ApiInfo = (YandexApiConfig, Session)
type YandexApiT m a = ReaderT ApiInfo m a


data YandexApiConfig = YandexApiConfig {
    _apikey      :: APIKey,
    _httpOptions :: Options
} deriving(Show)


data TranslateOptions = DetectLanguage
    deriving(Eq, Ord, Bounded, Enum)

data Format = Plain
            | HTML
    deriving(Eq, Ord, Bounded, Enum)


data TranslateParams = TranslateParams {
    _format  :: Format,
    _options :: [TranslateOptions]
} deriving(Show)


instance Show Direction where
    show (Direction (f, t)) = unpack f ++ "-" ++ unpack t


instance ToJSON Direction where
    toJSON = toJSON . show


instance FromJSON Direction where
    parseJSON = withText "Direction" $ \s ->
        case breakOn "-" s of
            (f, t)
                | "-" `isPrefixOf` t -> return $ Direction (f, drop 1 t)
                | otherwise -> fail "Can't parse language direction"


instance Show Format where
    show Plain = "plain"
    show HTML =  "html"


instance Show TranslateOptions where
    show DetectLanguage = "1"


makeLenses ''TranslateParams
makeLenses ''YandexApiConfig

_config :: Lens' ApiInfo YandexApiConfig
_config  = _1

_session :: Lens' ApiInfo Session
_session = _2


defaultParams :: TranslateParams
defaultParams = TranslateParams Plain []


instance Default TranslateParams where
    def = defaultParams


formatDirection :: Maybe Language -> Language -> Text
formatDirection (Just f) l =  f <> "-" <> l
formatDirection Nothing t = t


directionAsText :: Direction -> Text
directionAsText (Direction (f, l)) = f <> "-" <> l


configureApi :: APIKey -> YandexApiConfig
configureApi key = YandexApiConfig {_apikey=key, _httpOptions=opts}
  where
    opts = defaults & redirects .~ 0


runYandexApiT :: (MonadIO m) => Session -> YandexApiConfig -> YandexApiT m a -> m a
runYandexApiT sess conf act = runReaderT act (conf, sess)


runYandexApi :: (MonadIO m) => Session -> YandexApiConfig -> YandexApiT IO a -> m a
runYandexApi sess conf act = liftIO $ runYandexApiT sess conf act


runYandexApiSession :: YandexApiConfig -> YandexApiT IO a -> IO a
runYandexApiSession conf act = withAPISession (\sess -> runYandexApi sess conf act)