//
//  ProjectModels.swift
//  suixinkan
//
//  Created by Codex on 2026/6/24.
//

import Foundation

/// 项目详情实体，表示摄影师项目或店铺项目详情页需要展示的完整业务字段。
struct PhotographerProjectDetailResponse: Decodable, Identifiable, Hashable {
    let id: Int
    let scenicId: Int
    let cover: String
    let coverProject: String
    let coverCarousel: [String]
    let name: String
    let type: Int
    let typeName: String
    let status: Int
    let statusName: String
    let price: String
    let otPrice: String
    let priceDeposit: String
    let description: String
    let attrLabel: [String]
    let projectContent: String
    let sold: Int
    let unitName: String
    let materialNum: Int
    let photoNum: Int
    let videoNum: Int
    let createdAt: String
    let updatedAt: String
    let creatorName: String
    let creatorPhone: String
    let creatorRoleName: String
    let auditRemark: String
    let photogList: [ProjectPhotographerBrief]
    let scenicList: [ProjectScenicSpotBrief]

    /// 字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case id
        case scenicId = "scenic_id"
        case cover
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
        case name
        case type
        case typeName = "type_name"
        case status
        case statusName = "status_name"
        case price
        case otPrice = "ot_price"
        case priceDeposit = "price_deposit"
        case description
        case attrLabel = "attr_label"
        case projectContent = "project_content"
        case sold
        case unitName = "unit_name"
        case materialNum = "material_num"
        case photoNum = "photo_num"
        case videoNum = "video_num"
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case creatorName = "creator_name"
        case creatorPhone = "creator_phone"
        case creatorRoleName = "creator_role_name"
        case auditRemark = "audit_remark"
        case photogList = "photog_list"
        case scenicList = "scenic_list"
    }

    /// 宽松解码项目详情字段。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeProjectLossyInt(forKey: .id) ?? 0
        scenicId = try container.decodeProjectLossyInt(forKey: .scenicId) ?? 0
        cover = try container.decodeProjectLossyString(forKey: .cover)
        coverProject = try container.decodeProjectLossyString(forKey: .coverProject)
        coverCarousel = try container.decodeProjectLossyStringArray(forKey: .coverCarousel)
        name = try container.decodeProjectLossyString(forKey: .name)
        type = try container.decodeProjectLossyInt(forKey: .type) ?? 0
        typeName = try container.decodeProjectLossyString(forKey: .typeName)
        status = try container.decodeProjectLossyInt(forKey: .status) ?? 0
        statusName = try container.decodeProjectLossyString(forKey: .statusName)
        price = try container.decodeProjectLossyString(forKey: .price)
        otPrice = try container.decodeProjectLossyString(forKey: .otPrice)
        priceDeposit = try container.decodeProjectLossyString(forKey: .priceDeposit)
        description = try container.decodeProjectLossyString(forKey: .description)
        attrLabel = try container.decodeProjectLossyStringArray(forKey: .attrLabel)
        projectContent = try container.decodeProjectLossyString(forKey: .projectContent)
        sold = try container.decodeProjectLossyInt(forKey: .sold) ?? 0
        unitName = try container.decodeProjectLossyString(forKey: .unitName)
        materialNum = try container.decodeProjectLossyInt(forKey: .materialNum) ?? 0
        photoNum = try container.decodeProjectLossyInt(forKey: .photoNum) ?? 0
        videoNum = try container.decodeProjectLossyInt(forKey: .videoNum) ?? 0
        createdAt = try container.decodeProjectLossyString(forKey: .createdAt)
        updatedAt = try container.decodeProjectLossyString(forKey: .updatedAt)
        creatorName = try container.decodeProjectLossyString(forKey: .creatorName)
        creatorPhone = try container.decodeProjectLossyString(forKey: .creatorPhone)
        creatorRoleName = try container.decodeProjectLossyString(forKey: .creatorRoleName)
        auditRemark = try container.decodeProjectLossyString(forKey: .auditRemark)
        photogList = (try? container.decode([ProjectPhotographerBrief].self, forKey: .photogList)) ?? []
        scenicList = (try? container.decode([ProjectScenicSpotBrief].self, forKey: .scenicList)) ?? []
    }
}

/// 项目摄影师摘要实体，表示项目详情中的摄影师信息。
struct ProjectPhotographerBrief: Decodable, Identifiable, Hashable {
    let id: Int
    let photogUid: Int
    let nickname: String
    let avatar: String
    let orderNum: Int
    let completedOrderCount: Int

    /// 字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case id
        case photogUid = "photog_uid"
        case nickname
        case avatar
        case orderNum = "order_num"
        case completedOrderCount = "completed_order_count"
    }

    /// 宽松解码摄影师摘要。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeProjectLossyInt(forKey: .id) ?? 0
        photogUid = try container.decodeProjectLossyInt(forKey: .photogUid) ?? 0
        nickname = try container.decodeProjectLossyString(forKey: .nickname)
        avatar = try container.decodeProjectLossyString(forKey: .avatar)
        orderNum = try container.decodeProjectLossyInt(forKey: .orderNum) ?? 0
        completedOrderCount = try container.decodeProjectLossyInt(forKey: .completedOrderCount) ?? 0
    }
}

/// 项目打卡点摘要实体，表示项目关联的景点或打卡点。
struct ProjectScenicSpotBrief: Decodable, Identifiable, Hashable {
    let id: Int
    let name: String

    /// 字段映射。
    enum CodingKeys: String, CodingKey {
        case id
        case name
    }

    /// 宽松解码打卡点摘要。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeProjectLossyInt(forKey: .id) ?? 0
        name = try container.decodeProjectLossyString(forKey: .name)
    }
}

/// 摄影师项目创建或编辑请求实体。
struct ProjectCreateRequest: Encodable, Equatable {
    let id: Int?
    let type: Int
    let scenicId: Int
    let name: String
    let price: String
    let otPrice: String?
    let coverProject: String
    let coverCarousel: [String]?
    let description: String
    let attrLabel: [String]?
    let extra: ProjectCreateExtra
    let allowNFC: Int = 1

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case id
        case type
        case scenicId = "scenic_id"
        case name
        case price
        case otPrice = "ot_price"
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
        case description
        case attrLabel = "attr_label"
        case extra
        case allowNFC = "allow_nfc"
    }
}

/// 摄影师项目扩展配置实体，表示交付数量、押金和关联打卡点/摄影师。
struct ProjectCreateExtra: Encodable, Equatable {
    let priceDeposit: String
    let materialNum: Int
    let photoNum: Int
    let videoNum: Int
    let scenicSpotId: [Int]
    let photogUid: [Int]

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case priceDeposit = "price_deposit"
        case materialNum = "material_num"
        case photoNum = "photo_num"
        case videoNum = "video_num"
        case scenicSpotId = "scenic_spot_id"
        case photogUid = "photog_uid"
    }
}

/// 项目删除请求实体。
struct ProjectDeleteRequest: Encodable, Equatable {
    let id: Int
}

/// 店铺项目可管理景区实体。
struct StoreManagerScenicItem: Decodable, Identifiable, Hashable {
    let id: Int
    let name: String

    /// 字段映射。
    enum CodingKeys: String, CodingKey {
        case id
        case name
    }

    /// 宽松解码店铺项目景区。
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeProjectLossyInt(forKey: .id) ?? 0
        name = try container.decodeProjectLossyString(forKey: .name)
    }
}

/// 店铺项目套餐实体，表示多点位项目的套餐价格配置。
struct StoreManagerPackageItem: Codable, Hashable {
    let materialNum: Int
    let price: String

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case materialNum = "material_num"
        case price
    }
}

/// 店铺项目创建请求实体，用于多点位项目。
struct StoreManagerCreateRequest: Encodable, Equatable {
    let name: String
    let storeId: Int?
    let type: Int
    let description: String
    let coverProject: String?
    let coverCarousel: [String]?
    let projectRule: String?
    let scenicId: [Int]
    let settleSpotNum: Int
    let price: Double
    let priceMaterial: Double
    let pricePhoto: Double
    let priceVideo: Double
    let priceMaterialAll: Double?
    let packageList: [StoreManagerPackageItem]?
    let userId: Int
    let singleSpotMaterialNum: Int
    let singleSpotPhotoNum: Int
    let singleSpotVideoNum: Int

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case name
        case storeId = "store_id"
        case type
        case description
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
        case projectRule = "project_rule"
        case scenicId = "scenic_id"
        case settleSpotNum = "settle_spot_num"
        case price
        case priceMaterial = "price_material"
        case pricePhoto = "price_photo"
        case priceVideo = "price_video"
        case priceMaterialAll = "price_material_all"
        case packageList = "package"
        case userId = "user_id"
        case singleSpotMaterialNum = "single_spot_material_num"
        case singleSpotPhotoNum = "single_spot_photo_num"
        case singleSpotVideoNum = "single_spot_video_num"
    }
}

/// 店铺项目更新请求实体，用于多点位项目。
struct StoreManagerUpdateRequest: Encodable, Equatable {
    let id: Int
    let name: String
    let type: Int
    let description: String
    let coverProject: String?
    let coverCarousel: [String]?
    let projectRule: String?
    let scenicId: [Int]
    let settleSpotNum: Int
    let price: Double
    let priceMaterial: Double
    let pricePhoto: Double
    let priceVideo: Double
    let priceMaterialAll: Double?
    let packageList: [StoreManagerPackageItem]?
    let userId: Int
    let singleSpotMaterialNum: Int
    let singleSpotPhotoNum: Int
    let singleSpotVideoNum: Int

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case type
        case description
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
        case projectRule = "project_rule"
        case scenicId = "scenic_id"
        case settleSpotNum = "settle_spot_num"
        case price
        case priceMaterial = "price_material"
        case pricePhoto = "price_photo"
        case priceVideo = "price_video"
        case priceMaterialAll = "price_material_all"
        case packageList = "package"
        case userId = "user_id"
        case singleSpotMaterialNum = "single_spot_material_num"
        case singleSpotPhotoNum = "single_spot_photo_num"
        case singleSpotVideoNum = "single_spot_video_num"
    }
}

/// 店铺押金项目创建请求实体。
struct StoreManagerOfflineCreateRequest: Encodable, Equatable {
    let name: String
    let scenicId: Int
    let storeId: Int
    let description: String
    let price: Double
    let coverProject: String
    let coverCarousel: [String]

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case name
        case scenicId = "scenic_id"
        case storeId = "store_id"
        case description
        case price
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
    }
}

/// 店铺押金项目更新请求实体。
struct StoreManagerOfflineUpdateRequest: Encodable, Equatable {
    let id: Int
    let name: String
    let scenicId: Int
    let description: String
    let price: Double
    let coverProject: String?
    let coverCarousel: [String]?
    let storeId: Int?

    /// 请求字段映射，兼容后端下划线命名。
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case scenicId = "scenic_id"
        case description
        case price
        case coverProject = "cover_project"
        case coverCarousel = "cover_carousel"
        case storeId = "store_id"
    }
}

/// 项目本地待上传图片实体，保存 PhotosPicker 读取后的图片数据。
struct ProjectLocalImage: Identifiable, Equatable {
    let id = UUID()
    let data: Data
    let fileName: String
    let previewURL: String?
}

private extension KeyedDecodingContainer {
    /// 将 String、数字和 Bool 宽松解码为字符串。
    func decodeProjectLossyString(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 宽松解码为 Int。
    func decodeProjectLossyInt(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 decodeProjectLossyStringArray(forKey key: Key) throws -> [String] {
        if let values = try? decodeIfPresent([String].self, forKey: key) {
            return values
        }
        if let value = try? decodeIfPresent(String.self, forKey: key) {
            return value
                .components(separatedBy: CharacterSet(charactersIn: ",，\n"))
                .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
                .filter { !$0.isEmpty }
        }
        return []
    }
}
