//
//  MessageCenterModels.swift
//  suixinkan
//
//  Created by Codex on 2026/6/25.
//

import Foundation
import SwiftUI

/// 消息中心列表响应，使用 last_id 游标分页。
struct MessageListResponse: Decodable, Equatable {
    let hasMore: Bool
    let lastId: Int
    let items: [MessageEntity]

    enum CodingKeys: String, CodingKey {
        case hasMore = "has_more"
        case lastId = "last_id"
        case items
    }

    /// 创建空消息响应，主要用于测试和失败兜底。
    init(hasMore: Bool = false, lastId: Int = 0, items: [MessageEntity] = []) {
        self.hasMore = hasMore
        self.lastId = lastId
        self.items = items
    }

    /// 宽松解码分页状态，兼容后端数字/字符串/布尔类型不稳定。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        hasMore = try container.decodeLossyBool(forKey: .hasMore) ?? false
        lastId = try container.decodeLossyInt(forKey: .lastId) ?? 0
        items = try container.decodeIfPresent([MessageEntity].self, forKey: .items) ?? []
    }
}

/// 后端消息实体。
struct MessageEntity: Decodable, Equatable, Identifiable {
    let id: Int
    let type: Int
    let typeName: String
    let title: String
    let content: String
    let pushAt: String
    let createdAt: String
    let isRead: Bool

    enum CodingKeys: String, CodingKey {
        case id
        case type
        case typeName = "type_name"
        case title
        case content
        case pushAt = "push_at"
        case createdAt = "created_at"
        case isRead = "is_read"
    }

    /// 创建消息实体，主要用于测试。
    init(
        id: Int,
        type: Int,
        typeName: String = "",
        title: String = "",
        content: String = "",
        pushAt: String = "",
        createdAt: String = "",
        isRead: Bool = false
    ) {
        self.id = id
        self.type = type
        self.typeName = typeName
        self.title = title
        self.content = content
        self.pushAt = pushAt
        self.createdAt = createdAt
        self.isRead = isRead
    }

    /// 宽松解码消息字段，避免单条异常字段导致整页失败。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeLossyInt(forKey: .id) ?? 0
        type = try container.decodeLossyInt(forKey: .type) ?? 0
        typeName = try container.decodeLossyString(forKey: .typeName)
        title = try container.decodeLossyString(forKey: .title)
        content = try container.decodeLossyString(forKey: .content)
        pushAt = try container.decodeLossyString(forKey: .pushAt)
        createdAt = try container.decodeLossyString(forKey: .createdAt)
        isRead = try container.decodeLossyBool(forKey: .isRead) ?? false
    }
}

/// 删除消息请求体。
struct MessageDeleteRequest: Encodable {
    let id: Int
}

/// 页面展示用消息类型。
enum MessageType: Equatable {
    case order
    case writeOff
    case system

    /// 消息类型图标。
    var iconName: String {
        switch self {
        case .order:
            return "cart.fill"
        case .writeOff:
            return "qrcode.viewfinder"
        case .system:
            return "bell.badge.fill"
        }
    }

    /// 消息类型标题。
    var title: String {
        switch self {
        case .order:
            return "订单"
        case .writeOff:
            return "核销"
        case .system:
            return "系统"
        }
    }

    /// 消息类型颜色。
    var color: Color {
        switch self {
        case .order:
            return AppDesign.primary
        case .writeOff:
            return AppDesign.success
        case .system:
            return AppDesign.warning
        }
    }
}

/// 页面展示用消息项。
struct MessageItem: Identifiable, Equatable {
    let id: String
    let msgId: Int?
    let title: String
    let detail: String
    let time: String
    var isRead: Bool
    let type: MessageType
}

/// 消息筛选项。
enum MessageFilter: Int, CaseIterable, Identifiable {
    case all = 0
    case unread = 1

    var id: Int { rawValue }

    /// 筛选标题。
    var title: String {
        switch self {
        case .all:
            return "全部"
        case .unread:
            return "未读"
        }
    }
}

private extension KeyedDecodingContainer {
    /// 将 String、数字和 Bool 宽松解码为字符串。
    func decodeLossyString(forKey key: Key) throws -> String {
        if let value = try? decodeIfPresent(String.self, forKey: key) {
            return value
        }
        if let value = try? decodeIfPresent(Int.self, forKey: key) {
            return String(value)
        }
        if let value = try? decodeIfPresent(Double.self, forKey: key) {
            return String(value)
        }
        if let value = try? decodeIfPresent(Bool.self, forKey: key) {
            return value ? "1" : "0"
        }
        return ""
    }

    /// 将 String、数字和 Bool 宽松解码为 Int。
    func decodeLossyInt(forKey key: Key) throws -> Int? {
        if let value = try? decodeIfPresent(Int.self, forKey: key) {
            return value
        }
        if let value = try? decodeIfPresent(Double.self, forKey: key) {
            return Int(value)
        }
        if let value = try? decodeIfPresent(String.self, forKey: key),
           case let text = value.trimmingCharacters(in: .whitespacesAndNewlines),
           !text.isEmpty {
            return Int(text) ?? Int(Double(text) ?? 0)
        }
        if let value = try? decodeIfPresent(Bool.self, forKey: key) {
            return value ? 1 : 0
        }
        return nil
    }

    /// 将 String、数字和 Bool 宽松解码为 Bool。
    func decodeLossyBool(forKey key: Key) throws -> Bool? {
        if let value = try? decodeIfPresent(Bool.self, forKey: key) {
            return value
        }
        if let value = try? decodeIfPresent(Int.self, forKey: key) {
            return value != 0
        }
        if let value = try? decodeIfPresent(String.self, forKey: key),
           case let text = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased(),
           !text.isEmpty {
            if ["1", "true", "yes"].contains(text) { return true }
            if ["0", "false", "no"].contains(text) { return false }
        }
        return nil
    }
}
