content: {-# LANGUAGE DeriveAnyClass #-}
  {-# LANGUAGE DeriveGeneric #-}
  {-# LANGUAGE DerivingStrategies #-}
  {-# LANGUAGE DuplicateRecordFields #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Platform.Common.Types
    ( UserProfileResponse (..)
    , CreateThreadData (..)
    , AddCommentData (..)
    , AppColor (..)
    , ToColor (..)
    -- , ClassName
    , ThreadInfo (..)
    , FetchAllThreadsResponse (..)
    , Communities (..)
    , CommunityC (..)
    , LoginUserBody (..)
    , LoginUserResponse (..)
    , RegisterUserBody (..)
    , RegisterUserResponse (..)
    , CommentInfo (..)
    , NestedComment (..)
    , FetchCommentsResponse (..)
    , CreateCommentReqBody (..)
    , FetchVoteThreadsForUserReq (..)
    , FetchVoteComemntsForUserReq (..)
    , FetchVoteComments (..)
    , FetchVoteCommentsForUserResponse (..)
    , CreateThreadReqBody (..)
    , EditThreadData (..)
    , UpdateThreadReqBody (..)
    , UpdateCommentReqBody (..)
    , ChangePasswordBody (..)
    , DeleteUserBody (..)
    , AuthData (..)
    , AppConfig (..)
    , Environment (..)
    , LogLevel (..)
    , MinLogLevel
    , UserContext (..)
    , ThreadID
    , Vote
    , ThreadVotes
    ) where
  
  import Data.String.Conversions
  import Data.Text (Text)
  import Data.Time
  import System.Log.FastLogger
  import Text.Read (readMaybe)
  import Web.HttpApiData
  import Web.Hyperbole
  
  type ThreadID = Int
  type Vote = Bool -- True = UpVote, False = DownVote
  type ThreadVotes = [(ThreadID, Vote)]
  
  -- Information of currently loggedIn user
  data UserContext = UserContext
    { ucToken :: Text
    , ucUserProfile :: UserProfileResponse
    , ucUserThreadVotes :: ThreadVotes
    , ucUserCommentVotes :: [FetchVoteComments]
    }
    deriving (Show, Eq, Read, Generic, ToJSON, FromJSON)
  
  -- import Web.View.Types (ClassName)
  data LogLevel
    = LevelDebug
    | LevelInfo
    | LevelWarn
    | LevelError
    deriving (Eq, Ord, Generic)
  
  instance Show LogLevel where
    show LevelDebug = "[Debug]"
    show LevelInfo = "[Info]"
    show LevelWarn = "[Warn]"
    show LevelError = "[Error]"
  
  type MinLogLevel = LogLevel
  
  data Environment = Production | Development | Sandbox | Test | Local
    deriving (Generic, Eq, Ord, Show, ToJSON)
  
  data AppConfig = AppConfig
    { environment :: Environment
    , minLogLevel :: MinLogLevel
    , loggerSet :: LoggerSet
    }
  
  data UserProfileResponse = UserProfileResponse
    { userIDForUPR :: Int
    , userNameForUPR :: Text
    , userEmail :: Text
    , userCreatedAt :: Text
    }
    deriving (Show, Eq, Generic, FromJSON, Read, ToJSON)
  
  data CreateThreadData = CreateThreadData
    { mToken :: Maybe Text
    , mUserInfo :: Maybe UserProfileResponse
    , communityId :: Int
    , titleForCreateThread :: Text
    , content :: Text
    }
    deriving (Eq, Show, Read)
  
  data EditThreadData = EditThreadData
    { threadIdForEditThread :: Int
    , titleForEditThread :: Maybe Text
    , userIdForEditThread :: Int
    , descriptionForEditThread :: Maybe Text
    , communityIdForEditThread :: Maybe Int
    }
    deriving (Eq, Show, Read)
  
  data AddCommentData = AddCommentData
    { contentForAddComment :: Text
    , threadId :: Int
    , userToken :: Text
    , parentCommentIdForAddComment :: Maybe Int
    }
    deriving (Eq, Show, Read, Generic, ToJSON, FromJSON)
  
  data ThreadInfo = ThreadInfo
    { threadIDForThreadInfo :: Int
    , title :: Text
    , description :: Maybe Text
    , attachmentName :: Maybe Text
    , attachmentSize :: Maybe Int
    , createdAtForThreadInfo :: Text
    , userIDForThreadInfo :: Int
    , userNameForThreadInfo :: Text
    , communityIDForThreadInfo :: Int
    , communityNameForThreadInfo :: Text
    , upvoteCount :: Maybe Int
    , downvoteCount :: Maybe Int
    , commentCount :: Maybe Int
    }
    deriving (Show, Eq, Generic, FromJSON, Read, ToJSON)
  
  data FetchAllThreadsResponse = FetchAllThreadsResponse
    { threadsCount :: Int
    , threads :: [ThreadInfo]
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data AppColor
    = White
    | Light
    | GrayLight
    | GrayDark
    | Dark
    | Success
    | Danger
    | Warning
    | Primary
    | PrimaryLight
    | Secondary
    | SecondaryLight
    deriving (Show, Read)
  
  instance ToHttpApiData AppColor where
    toQueryParam c = cs (show c)
  
  instance FromHttpApiData AppColor where
    parseQueryParam t = do
      case readMaybe (cs t) of
        Nothing -> Left $ "Invalid AppColor: " <> t
        (Just c) -> pure c
  
  instance ToColor AppColor where
    colorValue White = "#FFF"
    colorValue Light = "#F2F2F3"
    colorValue GrayLight = "#E3E5E9"
    colorValue GrayDark = "#2С3С44"
    colorValue Dark = "#2E3842" -- "#232C41"
    colorValue Primary = "#4171b7"
    colorValue PrimaryLight = "#6D9BD3"
    colorValue Secondary = "#5D5A5C"
    colorValue SecondaryLight = "#9D999C"
    -- colorValue Success = "67C837"
    colorValue Success = "#149e5a"
    colorValue Danger = "#ef1509"
    colorValue Warning = "#e1c915"
  
  data Communities = Communities
    { communities :: [CommunityC]
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data CommunityC = CommunityC
    { communityName :: Text
    , communityID :: Int
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data LoginUserBody = LoginUserBody
    { emailForLogin :: Text
    , passwordForLogin :: Text
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON)
  
  data LoginUserResponse = LoginUserResponse
    { jwtToken :: Text
    , loginUserResponseMsg :: Text
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data RegisterUserBody = RegisterUserBody
    { userNameForRegister :: Text
    , emailForRegister :: Text
    , passwordForRegister :: Text
    , confirmPasswordForRegister :: Text
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON)
  
  data RegisterUserResponse = RegisterUserResponse
    { userIDForRUR :: Int
    , registerUserResponseMessage :: Text
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON)
  
  data CommentInfo = CommentInfo
    { commentIDForCommentInfo :: Int
    , commentContentForCommentInfo :: Text
    , userIDForCommentInfo :: Int
    , userNameForCommentInfo :: Text
    , threadIDForCommentInfo :: Int
    , createdAtForCommentInfo :: UTCTime
    , parentCommentIDForCommentInfo :: Maybe Int
    , commentUpvoteCount :: Maybe Int
    , commentDownvoteCount :: Maybe Int
    }
    deriving (Show, Eq, Generic, FromJSON, Read, ToJSON)
  
  newtype UpdateCommentReqBody = UpdateCommentReqBody
    {commentContentForUpdate :: Text}
    deriving (Generic, Show, Eq, Ord)
    deriving newtype (ToJSON, FromJSON)
  
  data NestedComment = NestedComment
    { mainComment :: CommentInfo
    , children :: [NestedComment]
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data FetchCommentsResponse = FetchCommentsResponse
    { commentsCount :: Int
    , comments :: [NestedComment]
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data CreateCommentReqBody = CreateCommentReqBody
    { threadIDForCommentCreate :: Int
    , commentContentForCreate :: Text
    , parentCommentIDForCreate :: Maybe Int
    }
    deriving (Show, Eq, Generic, ToJSON, FromJSON)
  
  data FetchVoteThreadsForUserReq = FetchVoteThreadsForUserReq
    { threadListForVotes :: [Int]
    }
    deriving (Show, Eq, Generic, ToJSON)
  
  data FetchVoteComemntsForUserReq = FetchVoteComemntsForUserReq
    { commentListForVotes :: [Int]
    }
    deriving (Show, Eq, Generic, ToJSON)
  
  data FetchVoteComments = FetchVoteComments
    { commentIDForFetchVote :: Int
    , isUpvote :: Bool
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON, Read)
  
  {-
  data CVote = CVote { commentIDForFetchVote :: Int, isUpvote :: Bool  }
      deriving (Show, Eq, Generic, FromJSON)
  newtype CVoteList = CVoteList [CVote]
      deriving (Show, Eq, Generic, FromJSON)
  -}
  
  data FetchVoteCommentsForUserResponse = FetchVoteCommentsForUserResponse
    { fetchVoteCommentsList :: [FetchVoteComments]
    }
    deriving (Show, Eq, Generic, FromJSON)
  
  data CreateThreadReqBody = CreateThreadReqBody
    { threadTitleForCreate :: Text
    , threadDescriptionForCreate :: Maybe Text
    , threadCommunityIDForCreate :: Int
    }
    deriving (Show, Eq, Generic, ToJSON, FromJSON)
  
  data UpdateThreadReqBody = UpdateThreadReqBody
    { threadIDForUpdate :: Int
    , threadTitleForUpdate :: Text
    , threadDescriptionForUpdate :: Maybe Text
    , threadCommunityIDForUpdate :: Int
    }
    deriving (Show, Eq, Generic, ToJSON, FromJSON)
  
  data ChangePasswordBody = ChangePasswordBody
    { oldPasswordForChangePass :: Text
    , newPasswordForChangePass :: Text
    , confirmPasswordForChangePass :: Text
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON)
  
  data DeleteUserBody = DeleteUserBody
    { passwordForDeleteUser :: Text
    , areUSure :: Bool
    }
    deriving (Show, Eq, Generic, FromJSON, ToJSON)
  
  data AuthData = AuthData
    { jToken :: Maybe Text
    }
    deriving (Generic, Show, Read, ToParam, FromParam, ToJSON, FromJSON)
  
  instance Session AuthData where
    sessionKey = "AuthData"
    cookiePath = Just []
  
  instance Default AuthData where
    def = AuthData Nothing
  