import Foundation

struct MessageReaction: Equatable {
    let userId: String
    let reaction: String
    let createdAt: Date
}

struct ForwardedFrom: Equatable {
    let sender: String
    let conversationId: String
    let messageId: String
}

enum ReactionEmoji {
    static let allowed = ["thumbsup", "heart", "laugh", "surprised", "sad", "thumbsdown"]
    static let display: [String: String] = [
        "thumbsup": "👍", "heart": "❤️", "laugh": "😂",
        "surprised": "😮", "sad": "😢", "thumbsdown": "👎",
    ]
}

struct Message: Identifiable, Equatable {
    let id: String
    let conversationId: String
    let senderId: String
    var senderUsername: String
    let createdAt: Date
    var text: String?
    var replyTo: String?
    var imageFileId: String?
    var file: FileInfo?
    var image: ImageInfo?
    var isDeleted: Bool
    var readBy: Set<String>
    var reactions: [MessageReaction]
    var forwardedFrom: ForwardedFrom?
    var pinnedAt: Date?
    var pinnedBy: String?

    /// Whether this is a self-sent message
    func isMine(currentUserId: String) -> Bool {
        senderId == currentUserId
    }

    static func == (lhs: Message, rhs: Message) -> Bool {
        lhs.id == rhs.id
    }
}

struct FileInfo: Equatable, Codable {
    let fileId: String
    let aesKey: String   // base64
    let iv: String       // base64
    let filename: String
    let size: Int
    let mimeType: String
}

struct ImageInfo: Equatable {
    let fileId: String
    let aesKey: String   // base64
    let iv: String       // base64
    let thumbnail: String? // base64 JPEG thumbnail
    let filename: String
    let size: Int
}

// MARK: - Cache Dictionary Conversion

extension Message {
    /// Convert to dictionary matching server JSON format for MessageCache storage
    func toCacheDict() -> [String: Any] {
        var dict: [String: Any] = [
            "message_id": id,
            "conversation_id": conversationId,
            "sender_id": senderId,
            "sender_username": senderUsername,
            "created_at": DateParsing.format(createdAt),
            "is_deleted": isDeleted,
        ]
        if let text = text { dict["text"] = text }
        if let replyTo = replyTo { dict["reply_to"] = replyTo }
        if let imageFileId = imageFileId { dict["image_file_id"] = imageFileId }
        if let file = file {
            dict["file"] = [
                "file_id": file.fileId,
                "aes_key": file.aesKey,
                "iv": file.iv,
                "filename": file.filename,
                "size": file.size,
                "mime_type": file.mimeType,
            ] as [String: Any]
        }
        if let image = image {
            var imgDict: [String: Any] = [
                "file_id": image.fileId,
                "aes_key": image.aesKey,
                "iv": image.iv,
                "filename": image.filename,
                "size": image.size,
            ]
            if let thumbnail = image.thumbnail { imgDict["thumbnail"] = thumbnail }
            dict["image"] = imgDict
        }
        if !readBy.isEmpty { dict["read_by"] = Array(readBy) }
        if !reactions.isEmpty {
            dict["reactions"] = reactions.map {
                ["user_id": $0.userId, "reaction": $0.reaction,
                 "created_at": DateParsing.format($0.createdAt)] as [String: Any]
            }
        }
        if let fwd = forwardedFrom {
            dict["forwarded_from"] = ["sender": fwd.sender,
                "conversation_id": fwd.conversationId,
                "message_id": fwd.messageId] as [String: Any]
        }
        if let pinnedAt { dict["pinned_at"] = DateParsing.format(pinnedAt) }
        if let pinnedBy { dict["pinned_by"] = pinnedBy }
        return dict
    }

    /// Create Message from cache dictionary (server JSON format)
    static func fromCacheDict(_ dict: [String: Any]) -> Message? {
        guard let id = dict["message_id"] as? String,
              let conversationId = dict["conversation_id"] as? String,
              let senderId = dict["sender_id"] as? String,
              let createdAtStr = dict["created_at"] as? String,
              let createdAt = DateParsing.parse(createdAtStr) else {
            return nil
        }

        let senderUsername = dict["sender_username"] as? String ?? ""

        var file: FileInfo?
        if let fileDict = dict["file"] as? [String: Any],
           let fileId = fileDict["file_id"] as? String {
            file = FileInfo(
                fileId: fileId,
                aesKey: fileDict["aes_key"] as? String ?? "",
                iv: fileDict["iv"] as? String ?? "",
                filename: fileDict["filename"] as? String ?? "",
                size: fileDict["size"] as? Int ?? 0,
                mimeType: fileDict["mime_type"] as? String ?? ""
            )
        }

        var image: ImageInfo?
        if let imgDict = dict["image"] as? [String: Any],
           let imgFileId = imgDict["file_id"] as? String {
            image = ImageInfo(
                fileId: imgFileId,
                aesKey: imgDict["aes_key"] as? String ?? "",
                iv: imgDict["iv"] as? String ?? "",
                thumbnail: imgDict["thumbnail"] as? String,
                filename: imgDict["filename"] as? String ?? "image.jpg",
                size: imgDict["size"] as? Int ?? 0
            )
        }

        let readBy: Set<String>
        if let readByArray = dict["read_by"] as? [String] {
            readBy = Set(readByArray)
        } else {
            readBy = []
        }

        var reactions: [MessageReaction] = []
        if let reactionsArr = dict["reactions"] as? [[String: Any]] {
            reactions = reactionsArr.compactMap { r in
                guard let userId = r["user_id"] as? String,
                      let reaction = r["reaction"] as? String else { return nil }
                let createdAt = (r["created_at"] as? String).flatMap { DateParsing.parse($0) } ?? Date()
                return MessageReaction(userId: userId, reaction: reaction, createdAt: createdAt)
            }
        }

        var forwardedFrom: ForwardedFrom?
        if let fwd = dict["forwarded_from"] as? [String: Any],
           let sender = fwd["sender"] as? String {
            forwardedFrom = ForwardedFrom(
                sender: sender,
                conversationId: fwd["conversation_id"] as? String ?? "",
                messageId: fwd["message_id"] as? String ?? ""
            )
        }

        let pinnedAt = (dict["pinned_at"] as? String).flatMap { DateParsing.parse($0) }
        let pinnedBy = dict["pinned_by"] as? String

        return Message(
            id: id,
            conversationId: conversationId,
            senderId: senderId,
            senderUsername: senderUsername,
            createdAt: createdAt,
            text: dict["text"] as? String,
            replyTo: dict["reply_to"] as? String,
            imageFileId: dict["image_file_id"] as? String,
            file: file,
            image: image,
            isDeleted: dict["is_deleted"] as? Bool ?? false,
            readBy: readBy,
            reactions: reactions,
            forwardedFrom: forwardedFrom,
            pinnedAt: pinnedAt,
            pinnedBy: pinnedBy
        )
    }
}
