module Reddit.Types.Message where

import Reddit.Parser
import Reddit.Types.Comment
import Reddit.Types.Listing
import Reddit.Types.Reddit
import Reddit.Types.Thing
import Reddit.Types.User
import Reddit.Utilities

import Control.Applicative
import Data.Aeson
import Data.Maybe
import Data.Monoid
import Data.Text (Text)
import Network.API.Builder.Query
import Prelude
import qualified Data.Vector as Vector

data Message = Message { messageID :: MessageKind
                       , new :: Bool
                       , to :: Username
                       , from :: Maybe Username
                       , subject :: Text
                       , body :: Text
                       , bodyHTML :: Text
                       , replies :: Listing MessageKind Message }
  deriving (Show, Read, Eq)

instance FromJSON Message where
  parseJSON (Object o) = do
    d <- o .: "data"
    Message <$> d .: "name"
            <*> d .: "new"
            <*> d .: "dest"
            <*> d .:? "author"
            <*> (d .: "link_title" <|> d .: "subject")
            <*> (unescape <$> d .: "body")
            <*> (unescape <$> d .: "body_html")
            <*> (fromMaybe (Listing Nothing Nothing []) <$> d .:? "replies")
  parseJSON _ = mempty

instance Thing Message where
  fullName m = fullName $ messageID m

instance ToQuery Message where
  toQuery k v = [(k, fullName v)]

isPrivateMessage :: Message -> Bool
isPrivateMessage m =
  case messageID m of
    PrivateMessage _ -> True
    _ -> False

isCommentReply :: Message -> Bool
isCommentReply m =
  case messageID m of
    CommentMessage _ -> True
    _ -> False

data MessageID = MessageID Text
  deriving (Show, Read, Eq, Ord)

instance FromJSON MessageID where
  parseJSON (String s) =
    MessageID <$> stripPrefix messagePrefix s
  parseJSON _ = mempty

instance Thing MessageID where
  fullName (MessageID m) = mconcat [messagePrefix, "_", m]

instance ToQuery MessageID where
  toQuery k m = toQuery k (fullName m)

instance FromJSON (POSTWrapped MessageID) where
  parseJSON (Object o) = do
    ms <- (o .: "json") >>= (.: "data") >>= (.: "things")
    case Vector.toList ms of
      [v] -> POSTWrapped <$> (v .: "data" >>= (.: "id"))
      _ -> mempty
  parseJSON _ = mempty

messagePrefix :: Text
messagePrefix = "t4"

data MessageKind = CommentMessage CommentID
                 | PrivateMessage MessageID
  deriving (Show, Read, Eq, Ord)

instance FromJSON MessageKind where
  parseJSON s =
    (CommentMessage <$> parseJSON s) <|>
    (PrivateMessage <$> parseJSON s)

instance Thing MessageKind where
  fullName (CommentMessage c) = fullName c
  fullName (PrivateMessage p) = fullName p

instance ToQuery MessageKind where
  toQuery k (CommentMessage c) = toQuery k c
  toQuery k (PrivateMessage p) = toQuery k p