//
//  PaymentModels.swift
//  suixinkan
//
//  Created by Codex on 2026/6/22.
//

import Foundation

/// 收款码响应实体，表示静态收款码 URL 和动态收款码基础 URL。
struct PayCodeResponse: Decodable, Equatable {
    let staticPayUrl: String
    let dynamicPayUrl: String

    /// 收款码 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case staticPayUrl = "static_pay_url"
        case dynamicPayUrl = "dynamic_pay_url"
    }

    /// 创建收款码响应实体，主要用于测试替身。
    init(staticPayUrl: String = "", dynamicPayUrl: String = "") {
        self.staticPayUrl = staticPayUrl
        self.dynamicPayUrl = dynamicPayUrl
    }

    /// 自定义解码，兼容后端把 URL 字段返回为数字或空值。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        staticPayUrl = try container.decodeLossyString(forKey: .staticPayUrl)
        dynamicPayUrl = try container.decodeLossyString(forKey: .dynamicPayUrl)
    }
}

/// 收款记录响应实体，包含后端日汇总和原始记录列表。
struct PaymentCollectionRecordResponse: Decodable, Equatable {
    let analyse: [PaymentCollectionRecordAnalyseItem]
    let list: [PaymentCollectionRecordItem]

    /// 收款记录响应 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case analyse
        case list
    }

    /// 创建收款记录响应实体，主要用于测试替身。
    init(analyse: [PaymentCollectionRecordAnalyseItem] = [], list: [PaymentCollectionRecordItem] = []) {
        self.analyse = analyse
        self.list = list
    }

    /// 自定义解码，兼容后端字段缺失。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        analyse = try container.decodeIfPresent([PaymentCollectionRecordAnalyseItem].self, forKey: .analyse) ?? []
        list = try container.decodeIfPresent([PaymentCollectionRecordItem].self, forKey: .list) ?? []
    }
}

/// 收款日汇总实体，表示某一天的收款笔数和金额。
struct PaymentCollectionRecordAnalyseItem: Decodable, Equatable, Identifiable {
    let date: String
    let orderCount: Int
    let orderAmountSum: String

    var id: String { date }

    /// 收款日汇总 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case date
        case orderCount = "order_count"
        case orderAmountSum = "order_amount_sum"
    }

    /// 创建收款日汇总实体，主要用于列表兜底和测试。
    init(date: String, orderCount: Int, orderAmountSum: String) {
        self.date = date
        self.orderCount = orderCount
        self.orderAmountSum = orderAmountSum
    }

    /// 自定义解码，兼容金额和数量字段类型不稳定。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        date = try container.decodeLossyString(forKey: .date)
        orderCount = try container.decodeLossyInt(forKey: .orderCount) ?? 0
        orderAmountSum = try container.decodeLossyString(forKey: .orderAmountSum)
    }
}

/// 收款记录实体，表示一次扫码收款订单。
struct PaymentCollectionRecordItem: Decodable, Equatable, Identifiable {
    let orderNumber: String
    let userPhone: String
    let orderAmount: String
    let createDate: String
    let createTime: String

    var id: String {
        orderNumber.isEmpty ? "\(createDate)-\(createTime)-\(orderAmount)" : orderNumber
    }

    /// 收款记录 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case orderNumber = "order_number"
        case userPhone = "user_phone"
        case orderAmount = "order_amount"
        case createDate = "create_date"
        case createTime = "create_time"
    }

    /// 创建收款记录实体，主要用于测试替身。
    init(orderNumber: String, userPhone: String, orderAmount: String, createDate: String, createTime: String) {
        self.orderNumber = orderNumber
        self.userPhone = userPhone
        self.orderAmount = orderAmount
        self.createDate = createDate
        self.createTime = createTime
    }

    /// 自定义解码，兼容订单号、手机号和金额字段类型不稳定。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        orderNumber = try container.decodeLossyString(forKey: .orderNumber)
        userPhone = try container.decodeLossyString(forKey: .userPhone)
        orderAmount = try container.decodeLossyString(forKey: .orderAmount)
        createDate = try container.decodeLossyString(forKey: .createDate)
        createTime = try container.decodeLossyString(forKey: .createTime)
    }
}

/// 收款记录分组实体，表示一个日期下的汇总和明细。
struct PaymentCollectionRecordGroup: Equatable, Identifiable {
    let analyse: PaymentCollectionRecordAnalyseItem
    let items: [PaymentCollectionRecordItem]

    var id: String { analyse.id }
}

/// 收款状态实体，表示当前动态收款轮询结果。
enum PaymentCollectionStatus: Equatable {
    case idle
    case waiting
    case success(PaymentCollectionRecordItem)
    case failed(String)
}

private extension KeyedDecodingContainer {
    /// 将字符串、数字或空值宽松解码为字符串。
    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 value.truncatingRemainder(dividingBy: 1) == 0 ? String(Int(value)) : String(value)
        }
        return ""
    }

    /// 将字符串或数字宽松解码为整数。
    func decodeLossyInt(forKey key: Key) throws -> Int? {
        if let value = try decodeIfPresent(Int.self, forKey: key) {
            return value
        }
        if let value = try decodeIfPresent(String.self, forKey: key) {
            let text = value.trimmingCharacters(in: .whitespacesAndNewlines)
            if let intValue = Int(text) {
                return intValue
            }
            if let doubleValue = Double(text) {
                return Int(doubleValue)
            }
        }
        if let value = try decodeIfPresent(Double.self, forKey: key) {
            return Int(value)
        }
        return nil
    }
}
