{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Kurita.Bot.Types where

import           Data.Aeson
import           Data.Text              (Text)
import qualified Data.Text              as T

import           Data.Aeson.Types       (Parser)

import           Network.Linklater.Types (APIToken, Channel, Config)

import           Kurita.Prompt.Internal

data BotConfig = BotConfig {
  botConfigToken :: APIToken
, botConfigHook  :: (Channel, Config)
}

data BotCommand =
    AddPrompt Prompt -- Add a prompt
  | SetLive Prompt
  | List Int Int
  | CurrentBattle -- Current battle
  | AddData Text Text
  | RemoveData Text Text
  | SearchPrompts Text
  | TestPrompt Int
  | SetPrompt Int
  | LastRoundWinners
  | NextUp
  deriving (Eq, Ord, Show)

data BotEvent =
    EventMessage Message
  | EventMessageReply MessageReply
  | ReactionAdded Reaction
  | ReactionRemoved Reaction
  deriving (Eq, Ord, Show)

instance FromJSON BotEvent where
  parseJSON =
    withObject "BotEvent" $ \o -> do
      (messageType :: Text) <- o .: "type"
      case messageType of
        "message" -> do
          (st :: Maybe Text) <- o .:? "subtype"
          case st of
            (Just "message_replied") ->
              EventMessageReply <$> parseObject o
            (Just subtype) ->
              fail $ "Message sub_type " <> T.unpack subtype <> " not supported"
            Nothing ->
              EventMessage <$> parseObject o
        "reaction_added" ->
          ReactionAdded <$> parseObject o
        "ReactionRemoved" ->
          ReactionRemoved <$> parseObject o
        _ -> fail $ "Messages of type " <> T.unpack messageType <> " are not supported"

parseObject :: FromJSON a => Object -> Parser a
parseObject = parseJSON . Object

data MessageReply = MessageReply {
  messageReplyTimestamp :: TimeStamp
, messageReplyMessage   :: Message
} deriving (Eq, Ord, Show)

instance FromJSON MessageReply where
  parseJSON =
    withObject "MessageReply" $ \o ->
      MessageReply
        <$> o .: "ts"
        <*> o .: "message"

data Reaction = Reaction {
  reactionValue           :: Text
, reactionTargetTimestamp :: TimeStamp
, reactionUser            :: Text
} deriving (Eq, Ord, Show)

instance FromJSON Reaction where
  parseJSON =
    withObject "Reaction" $ \o -> do
      reaction <- o .: "reaction"
      item <- o .: "item"
      ts <- withObject "Item" (.: "ts") item
      user <- o .: "user"
      pure $ Reaction reaction ts user

data Message = Message {
  messageText      :: Text
, messageUser      :: Text
, messageTimestamp :: TimeStamp
} deriving (Eq, Ord, Show)

instance FromJSON Message where
  parseJSON =
    withObject "Message" $ \o ->
      Message
        <$> o .: "text"
        <*> o .: "user"
        <*> o .: "ts"

newtype TimeStamp = TimeStamp {
  unTimeStamp :: Text
} deriving (Eq, Ord, Show)

instance FromJSON TimeStamp where
  parseJSON j = TimeStamp <$> parseJSON j