//
//  ProfileSpaceModels.swift
//  suixinkan
//
//  Created by Codex on 2026/6/29.
//

import Foundation

/// 摄影师个人空间配置响应，表示当前景区下的公开展示资料和接单配置。
struct ProfileSpaceInfoResponse: Decodable, Equatable {
    let id: Int
    let scenicId: Int
    let photogUid: Int
    let realName: String
    let nickname: String
    let avatar: String
    let scenicCertification: [String]
    let description: String
    let attrLabel: [String]
    let shootLabel: [String]
    let cameraDevice: [String]
    let businessStartTime: String
    let businessEndTime: String
    let holidayStartTime: String
    let holidayEndTime: String
    let businessRange: [Int]
    let acceptOrderStatus: Int
    let schedule: [String: [ScheduleItem]]

    /// 响应 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case id
        case scenicId = "scenic_id"
        case photogUid = "photog_uid"
        case realName = "real_name"
        case nickname
        case avatar
        case scenicCertification = "scenic_certification"
        case description
        case attrLabel = "attr_label"
        case shootLabel = "shoot_label"
        case cameraDevice = "camera_device"
        case businessStartTime = "business_start_time"
        case businessEndTime = "business_end_time"
        case holidayStartTime = "holiday_start_time"
        case holidayEndTime = "holiday_end_time"
        case businessRange = "business_range"
        case acceptOrderStatus = "accept_order_status"
        case schedule
    }

    /// 宽松解码后端资料字段，兼容 null、数字字符串和缺失数组。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeProfileSpaceLossyInt(forKey: .id) ?? 0
        scenicId = try container.decodeProfileSpaceLossyInt(forKey: .scenicId) ?? 0
        photogUid = try container.decodeProfileSpaceLossyInt(forKey: .photogUid) ?? 0
        realName = try container.decodeProfileSpaceLossyString(forKey: .realName)
        nickname = try container.decodeProfileSpaceLossyString(forKey: .nickname)
        avatar = try container.decodeProfileSpaceLossyString(forKey: .avatar)
        scenicCertification = try container.decodeProfileSpaceStringArray(forKey: .scenicCertification)
        description = try container.decodeProfileSpaceLossyString(forKey: .description)
        attrLabel = try container.decodeProfileSpaceStringArray(forKey: .attrLabel)
        shootLabel = try container.decodeProfileSpaceStringArray(forKey: .shootLabel)
        cameraDevice = try container.decodeProfileSpaceStringArray(forKey: .cameraDevice)
        businessStartTime = try container.decodeProfileSpaceLossyString(forKey: .businessStartTime)
        businessEndTime = try container.decodeProfileSpaceLossyString(forKey: .businessEndTime)
        holidayStartTime = try container.decodeProfileSpaceLossyString(forKey: .holidayStartTime)
        holidayEndTime = try container.decodeProfileSpaceLossyString(forKey: .holidayEndTime)
        businessRange = try container.decodeProfileSpaceIntArray(forKey: .businessRange)
        acceptOrderStatus = try container.decodeProfileSpaceLossyInt(forKey: .acceptOrderStatus) ?? 0
        schedule = (try? container.decodeIfPresent([String: [ScheduleItem]].self, forKey: .schedule)) ?? [:]
    }
}

/// 摄影师个人空间配置更新请求。
struct UpdateProfileSpaceRequest: Encodable, Equatable {
    let scenicId: String
    let description: String
    let cameraDevice: [String]
    let attrLabel: [String]
    let shootLabel: [String]
    let businessStartTime: String
    let businessEndTime: String
    let holidayStartTime: String
    let holidayEndTime: String
    let businessRange: [Int]
    let acceptOrderStatus: Int

    /// 请求 JSON 字段映射。
    enum CodingKeys: String, CodingKey {
        case scenicId = "scenic_id"
        case description
        case cameraDevice = "camera_device"
        case attrLabel = "attr_label"
        case shootLabel = "shoot_label"
        case businessStartTime = "business_start_time"
        case businessEndTime = "business_end_time"
        case holidayStartTime = "holiday_start_time"
        case holidayEndTime = "holiday_end_time"
        case businessRange = "business_range"
        case acceptOrderStatus = "accept_order_status"
    }
}

/// 个人空间接单状态枚举，承接后端 1-4 状态值。
enum ProfileSpaceOrderStatus: Int, CaseIterable, Identifiable {
    case accepting = 1
    case paused = 2
    case full = 3
    case offline = 4

    var id: Int { rawValue }

    /// 状态展示文案。
    var title: String {
        switch self {
        case .accepting: "可接单"
        case .paused: "暂停接单"
        case .full: "已约满"
        case .offline: "下线"
        }
    }
}

/// 个人空间配置草稿，用于比较是否有未保存改动。
struct ProfileSpaceEditableSnapshot: Equatable {
    var nickname: String
    var description: String
    var attrLabel: [String]
    var shootLabel: [String]
    var cameraDevice: [String]
    var businessStartTime: Date?
    var businessEndTime: Date?
    var holidayStartTime: Date?
    var holidayEndTime: Date?
    var acceptOrderStatus: Int
    var avatarURL: String
}

/// 个人空间配置表单校验错误。
enum ProfileSpaceValidationError: LocalizedError, Equatable {
    case missingScenic
    case emptyNickname
    case emptyLabel
    case duplicateLabel
    case labelTooLong
    case labelLimit
    case missingWorkdayStart
    case missingWorkdayEnd
    case missingHolidayStart
    case missingHolidayEnd
    case invalidWorkdayTime
    case invalidHolidayTime

    var errorDescription: String? {
        switch self {
        case .missingScenic: "当前缺少景区信息"
        case .emptyNickname: "请输入昵称"
        case .emptyLabel: "标签不能为空"
        case .duplicateLabel: "标签已存在"
        case .labelTooLong: "标签最多20个字符"
        case .labelLimit: "最多8个标签"
        case .missingWorkdayStart: "请输入工作日开始时间"
        case .missingWorkdayEnd: "请输入工作日结束时间"
        case .missingHolidayStart: "请输入节假日开始时间"
        case .missingHolidayEnd: "请输入节假日结束时间"
        case .invalidWorkdayTime: "工作日开始时间必须早于结束时间"
        case .invalidHolidayTime: "节假日开始时间必须早于结束时间"
        }
    }
}

extension Date {
    /// 将日期格式化为后端需要的 HH:mm:ss 时间文本。
    var profileSpaceTimeText: String {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "zh_CN")
        formatter.dateFormat = "HH:mm:ss"
        return formatter.string(from: self)
    }

    /// 将日期格式化为空间配置页面展示的 HH:mm 文本。
    var profileSpaceHourMinuteText: String {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "zh_CN")
        formatter.dateFormat = "HH:mm"
        return formatter.string(from: self)
    }

    /// 根据 HH:mm:ss 或 HH:mm 文本生成仅含时间部分的 Date。
    static func profileSpaceTime(from text: String) -> Date? {
        let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty, trimmed != "00:00:00" else { return nil }
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "zh_CN")
        formatter.dateFormat = trimmed.count == 5 ? "HH:mm" : "HH:mm:ss"
        return formatter.date(from: trimmed)
    }
}

private extension KeyedDecodingContainer {
    /// 将 String、数字和 Bool 宽松解码为字符串。
    func decodeProfileSpaceLossyString(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、Double 和 Int 宽松解码为整数。
    func decodeProfileSpaceLossyInt(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) {
            let text = value.trimmingCharacters(in: .whitespacesAndNewlines)
            return Int(text) ?? Double(text).map(Int.init)
        }
        return nil
    }

    /// 宽松解码字符串数组，过滤空白项。
    func decodeProfileSpaceStringArray(forKey key: Key) throws -> [String] {
        guard let values = try? decodeIfPresent([String].self, forKey: key) else { return [] }
        return values
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }
    }

    /// 宽松解码整数数组。
    func decodeProfileSpaceIntArray(forKey key: Key) throws -> [Int] {
        if let values = try? decodeIfPresent([Int].self, forKey: key) {
            return values
        }
        if let values = try? decodeIfPresent([String].self, forKey: key) {
            return values.compactMap { Int($0.trimmingCharacters(in: .whitespacesAndNewlines)) }
        }
        return []
    }
}
