{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}

module ChatWork.Types.Rooms (
    -- Response Types

      Rooms
    , RoomDetail(..)
    , RoomIdWrap(..)
    , Members
    , Member(..)
    , MembersPermission(..)
    , Messages
    , Message(..)
    , MessageIdWrap(..)
    , RoomTasks
    , RoomTask(..)
    , TaskIdsWrap(..)
    , Files
    , File(..)
    -- Request Parameter Types

    , CreateRoomParams(..)
    , UpdateRoomParams(..)
    , RoomMembersParams(..)
    , GetTasksParams(..)
    , CreateTaskParams(..)
    , DeleteRoomActionType(..)
    , Force
    , MessageBody
    , CreateUrlFlag
    ) where

import           ChatWork.Types.Base         (Account, IconPreset, TaskStatus)
import           ChatWork.Utils              (strLength)
import           Data.Aeson                  (FromJSON (..), ToJSON (..),
                                              genericParseJSON, genericToJSON)
import           Data.Aeson.Casing           (aesonDrop, snakeCase)
import           Data.Text                   (Text, pack)
import           GHC.Generics                (Generic)
import           Web.FormUrlEncoded
import           Web.HttpApiData

type Rooms = [RoomDetail]

data RoomDetail = RoomDetail
                { roomDetailToRoomId         :: Int
                , roomDetailToName           :: Text
                , roomDetailToType           :: Text
                , roomDetailToRole           :: Text
                , roomDetailToSticky         :: Bool
                , roomDetailToUnreadNum      :: Int
                , roomDetailToMentionNum     :: Int
                , roomDetailToMytaskNum      :: Int
                , roomDetailToMessageNum     :: Int
                , roomDetailToFileNum        :: Int
                , roomDetailToTaskNum        :: Int
                , roomDetailToIconPath       :: Text
                , roomDetailToLastUpdateTime :: Int
                , roomDetailToDescription    :: Maybe Text
                } deriving (Eq, Show, Generic)

instance ToJSON RoomDetail where
  toJSON = genericToJSON $ aesonDrop (strLength "roomDetailTo") snakeCase
instance FromJSON RoomDetail where
  parseJSON = genericParseJSON $ aesonDrop (strLength "roomDetailTo") snakeCase

newtype RoomIdWrap = RoomIdWrap { getRoomId :: Int } deriving (Eq, Show, Generic)

instance ToJSON RoomIdWrap where
  toJSON = genericToJSON $ aesonDrop (strLength "get") snakeCase
instance FromJSON RoomIdWrap where
  parseJSON = genericParseJSON $ aesonDrop (strLength "get") snakeCase

type Members = [Member]

data Member = Member
            { memberToAccountId        :: Int
            , memberToRole             :: Text
            , memberToName             :: Text
            , memberToChatworkId       :: Text
            , memberToOrganizationId   :: Int
            , memberToOrganizationName :: Text
            , memberToDepartment       :: Text
            , memberToAvatarImageUrl   :: Text
            } deriving (Eq, Show, Generic)

instance ToJSON Member where
  toJSON = genericToJSON $ aesonDrop (strLength "memberTo") snakeCase
instance FromJSON Member where
  parseJSON = genericParseJSON $ aesonDrop (strLength "memberTo") snakeCase

data MembersPermission = MembersPermission
                 { membersPermissionToAdmin    :: [Int]
                 , membersPermissionToMember   :: [Int]
                 , membersPermissionToReadonly :: [Int]
                 } deriving (Eq, Show, Generic)

instance ToJSON MembersPermission where
  toJSON = genericToJSON $ aesonDrop (strLength "membersPermissionTo") snakeCase
instance FromJSON MembersPermission where
  parseJSON = genericParseJSON $ aesonDrop (strLength "membersPermissionTo") snakeCase

type Messages = [Message]

data Message = Message
             { messageToMessageId  :: Text
             , messageToAccount    :: Account
             , messageToBody       :: Text
             , messageToSendTime   :: Int
             , messageToUpdateTime :: Int
             } deriving (Eq, Show, Generic)

instance ToJSON Message where
  toJSON = genericToJSON $ aesonDrop (strLength "messageTo") snakeCase
instance FromJSON Message where
  parseJSON = genericParseJSON $ aesonDrop (strLength "messageTo") snakeCase

newtype MessageIdWrap = MessageIdWrap { getMessageId :: Text } deriving (Eq, Show, Generic)

instance ToJSON MessageIdWrap where
  toJSON = genericToJSON $ aesonDrop (strLength "get") snakeCase
instance FromJSON MessageIdWrap where
  parseJSON = genericParseJSON $ aesonDrop (strLength "get") snakeCase

type RoomTasks = [RoomTask]

data RoomTask = RoomTask
              { roomTaskToTaskId            :: Int
              , roomTaskToAccount           :: Account
              , roomTaskToAssignedByAccount :: Account
              , roomTaskToMessageId         :: Text
              , roomTaskToBody              :: Text
              , roomTaskToLimitTime         :: Int
              , roomTaskToStatus            :: Text
              } deriving (Eq, Show, Generic)

instance ToJSON RoomTask where
  toJSON = genericToJSON $ aesonDrop (strLength "roomTaskTo") snakeCase
instance FromJSON RoomTask where
  parseJSON = genericParseJSON $ aesonDrop (strLength "roomTaskTo") snakeCase

newtype TaskIdsWrap = TaskIdsWrap { getTaskIds :: [Int] } deriving (Eq, Show, Generic)

instance ToJSON TaskIdsWrap where
  toJSON = genericToJSON $ aesonDrop (strLength "get") snakeCase
instance FromJSON TaskIdsWrap where
  parseJSON = genericParseJSON $ aesonDrop (strLength "get") snakeCase

type Files = [File]

data File = File
          { fileToFileId     :: Int
          , fileToAccount    :: Account
          , fileToMessageId  :: Text
          , fileToFilename   :: Text
          , fileToFilesize   :: Int
          , fileToUploadTime :: Int
          } deriving (Eq, Show, Generic)

instance ToJSON File where
  toJSON = genericToJSON $ aesonDrop (strLength "fileTo") snakeCase
instance FromJSON File where
  parseJSON = genericParseJSON $ aesonDrop (strLength "fileTo") snakeCase

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#POST-rooms>

data CreateRoomParams = CreateRoomParams
                      { cRoomDescription    :: Maybe Text
                      , cIconPreset         :: Maybe IconPreset
                      , cMembersAdminIds    :: [Int]
                      , cMembersMemberIds   :: Maybe [Int]
                      , cMembersReadonlyIds :: Maybe [Int]
                      , cRoomName           :: Text
                      } deriving (Show)

instance FromForm CreateRoomParams where
  fromForm f = CreateRoomParams
           <$> parseMaybe "description" f
           <*> parseMaybe "icon_preset" f
           <*> parseUnique "members_admin_ids" f
           <*> parseMaybe "members_member_ids" f
           <*> parseMaybe "members_readonly_ids" f
           <*> parseUnique "name" f

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#PUT-rooms-room_id>

data UpdateRoomParams = UpdateRoomParams
                      { uRoomDescription :: Maybe Text
                      , uIconPreset      :: Maybe IconPreset
                      , uRoomName        :: Maybe Text
                      } deriving (Show)

instance FromForm UpdateRoomParams where
  fromForm f = UpdateRoomParams
           <$> parseMaybe "description" f
           <*> parseMaybe "icon_preset" f
           <*> parseMaybe "name" f

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#PUT-rooms-room_id-members>

data RoomMembersParams = RoomMembersParams
                       { getAdminIds    :: [Int]
                       , getMemberIds   :: Maybe [Int]
                       , getReadonlyIds :: Maybe [Int]
                       } deriving (Show)

instance FromForm RoomMembersParams where
  fromForm f = RoomMembersParams
           <$> parseUnique "members_admin_ids" f
           <*> parseMaybe "members_member_ids" f
           <*> parseMaybe "members_readonly_ids" f

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms-room_id-tasks>

data GetTasksParams = GetTasksParams
                   { getTaskAccountId           :: Maybe Int
                   , getTaskAssignedByAccountId :: Maybe Int
                   , getTaskStatus              :: Maybe TaskStatus
                   } deriving (Show)

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#POST-rooms-room_id-tasks>

data CreateTaskParams = CreateTaskParams
                      { getTaskBody  :: Text
                      , getTaskLimit :: Maybe Int
                      , getTaskToIds :: [Int]
                      } deriving (Show)

instance FromForm CreateTaskParams where
  fromForm f = CreateTaskParams
           <$> parseUnique "body" f
           <*> parseMaybe "limit" f
           <*> parseUnique "to_ids" f

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#DELETE-rooms-room_id>

data DeleteRoomActionType = LeaveRoom
                          | DeleteRoom
                          deriving (Bounded, Enum, Eq)

instance Show DeleteRoomActionType where
  show LeaveRoom  = "leave"
  show DeleteRoom = "delete"

instance FromForm DeleteRoomActionType where
  fromForm = parseUnique "action_type"

instance ToHttpApiData DeleteRoomActionType where
  toUrlPiece = pack . show

instance FromHttpApiData DeleteRoomActionType where
  parseUrlPiece = parseBoundedUrlPiece

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms-room_id-messages>

type Force = Bool

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#POST-rooms-room_id-messages>

type MessageBody = Text

-- |

-- see: <http://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms-room_id-files-file_id>

type CreateUrlFlag = Bool