//
//  SampleManagementModels.swift
//  suixinkan
//

import Foundation

/// 样片列表筛选状态，对齐 Android `SampleListViewModel` 的四档筛选。
enum SampleFilterStatus: Int, CaseIterable, Sendable, Equatable {
    case all = 0
    case approved = 1
    case pending = 2
    case rejected = 3

    /// 展示文案。
    var title: String {
        switch self {
        case .all: "全部"
        case .approved: "已通过"
        case .pending: "待审核"
        case .rejected: "未通过"
        }
    }

    /// 服务端 `status` 参数，Android 固定映射为：全部 4、已审核 1、待审核 0、未通过 2。
    var apiStatus: Int {
        switch self {
        case .all: 4
        case .approved: 1
        case .pending: 0
        case .rejected: 2
        }
    }
}

/// 样片素材类型，对齐 Android `mediaType`：1 图片，2 视频。
enum SampleMediaType: Int, CaseIterable, Sendable, Equatable {
    case image = 1
    case video = 2

    /// 展示文案。
    var title: String {
        switch self {
        case .image: "图片"
        case .video: "视频"
        }
    }

    /// 最大可选数量。
    var maxCount: Int {
        switch self {
        case .image: 9
        case .video: 1
        }
    }

    /// OSS 文件类型，Android `UploadTaskEntity.fileType` 中视频为 1、图片为 2。
    var uploadFileType: Int {
        switch self {
        case .image: 2
        case .video: 1
        }
    }
}

/// 样片列表项，对齐 Android `MaterialItemEntity`。
struct SampleMaterialItem: Decodable, Sendable, Equatable, Hashable, Identifiable {
    let id: Int
    let name: String
    let coverUrl: String
    let createdAt: String
    let status: Int
    let downloadCount: Int
    let likesCount: Int
    let collectCount: Int
    let shareCount: Int
    let scenicSpotName: String
    let projectName: String
    let listingStatus: Int

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case coverUrl = "cover_url"
        case createdAt = "created_at"
        case status
        case downloadCount = "download_count"
        case likesCount = "likes_count"
        case collectCount = "collect_count"
        case shareCount = "share_count"
        case scenicSpotName = "scenic_spot_name"
        case projectName = "project_name"
        case listingStatus = "listing_status"
    }

    init(
        id: Int = 0,
        name: String = "",
        coverUrl: String = "",
        createdAt: String = "",
        status: Int = 0,
        downloadCount: Int = 0,
        likesCount: Int = 0,
        collectCount: Int = 0,
        shareCount: Int = 0,
        scenicSpotName: String = "",
        projectName: String = "",
        listingStatus: Int = 0
    ) {
        self.id = id
        self.name = name
        self.coverUrl = coverUrl
        self.createdAt = createdAt
        self.status = status
        self.downloadCount = downloadCount
        self.likesCount = likesCount
        self.collectCount = collectCount
        self.shareCount = shareCount
        self.scenicSpotName = scenicSpotName
        self.projectName = projectName
        self.listingStatus = listingStatus
    }

    /// 是否已上架。
    var isListed: Bool { listingStatus == 1 }
}

/// 样片列表响应，对齐 Android `MaterialListResponse`。
struct SampleMaterialListResponse: Decodable, Sendable, Equatable {
    let total: Int
    let list: [SampleMaterialItem]
    let order: SampleMaterialOrderInfo?

    init(total: Int = 0, list: [SampleMaterialItem] = [], order: SampleMaterialOrderInfo? = nil) {
        self.total = total
        self.list = list
        self.order = order
    }
}

/// 样片列表统计信息，对齐 Android `MaterialOrderInfo`。
struct SampleMaterialOrderInfo: Decodable, Sendable, Equatable {
    let totalNum: Int
    let avgOrderAmount: String
    let refundTotal: String
    let avgChange: Int

    enum CodingKeys: String, CodingKey {
        case totalNum = "total_num"
        case avgOrderAmount = "avg_order_amount"
        case refundTotal = "refund_total"
        case avgChange = "avg_change"
    }

    init(totalNum: Int = 0, avgOrderAmount: String = "0", refundTotal: String = "0", avgChange: Int = 0) {
        self.totalNum = totalNum
        self.avgOrderAmount = avgOrderAmount
        self.refundTotal = refundTotal
        self.avgChange = avgChange
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        totalNum = try container.decodeIfPresent(Int.self, forKey: .totalNum) ?? 0
        avgOrderAmount = try container.decodeIfPresent(String.self, forKey: .avgOrderAmount) ?? "0"
        refundTotal = try container.decodeIfPresent(String.self, forKey: .refundTotal) ?? "0"
        avgChange = try container.decodeIfPresent(Int.self, forKey: .avgChange) ?? 0
    }
}

/// 样片详情响应，对齐 Android `SampleDetailResponse`。
struct SampleDetail: Decodable, Sendable, Equatable {
    let id: Int
    let name: String?
    let type: Int?
    let coverUrl: String?
    let coverSize: Int?
    let description: String?
    let scenicSpotId: Int?
    let scenicAreaId: Int?
    let uploaderId: Int?
    let status: Int
    let likesCount: Int
    let downloadCount: Int
    let collectCount: Int
    let createdAt: String?
    let updatedAt: String?
    let deletedAt: String?
    let listingStatus: Int
    let reviewNotes: String?
    let reviewTime: String?
    let reviewerId: Int?
    let provinceId: Int?
    let cityId: Int?
    let shareCount: Int
    let uploaderName: String?
    let uploaderAvatar: String?
    let uploaderDescription: String?
    let platformCertification: Bool
    let scenicCertification: Bool
    let mediaList: [SampleDetailMediaItem]?
    let scenicName: String?
    let scenicCoverImg: String?
    let scenicPlanesNum: Int
    let scenicPhotographerNum: Int
    let projectCover: String?
    let projectName: String?
    let projectPrice: Double?
    let projectPriceDeposit: String?
    let reviewer: String?

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case type
        case coverUrl = "cover_url"
        case coverSize = "cover_size"
        case description
        case scenicSpotId = "scenic_spot_id"
        case scenicAreaId = "scenic_area_id"
        case uploaderId = "uploader_id"
        case status
        case likesCount = "likes_count"
        case downloadCount = "download_count"
        case collectCount = "collect_count"
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case deletedAt = "deleted_at"
        case listingStatus = "listing_status"
        case reviewNotes = "review_notes"
        case reviewTime = "review_time"
        case reviewerId = "reviewer_id"
        case provinceId = "province_id"
        case cityId = "city_id"
        case shareCount = "share_count"
        case uploaderName = "uploader_name"
        case uploaderAvatar = "uploader_avatar"
        case uploaderDescription = "uploader_description"
        case platformCertification = "platform_certification"
        case scenicCertification = "scenic_certification"
        case mediaList = "media_list"
        case scenicName = "scenic_name"
        case scenicCoverImg = "scenic_cover_img"
        case scenicPlanesNum = "scenic_planes_num"
        case scenicPhotographerNum = "scenic_photographer_num"
        case projectCover = "project_cover"
        case projectName = "project_name"
        case projectPrice = "project_price"
        case projectPriceDeposit = "project_price_deposit"
        case reviewer
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
        name = try container.decodeIfPresent(String.self, forKey: .name)
        type = try container.decodeIfPresent(Int.self, forKey: .type)
        coverUrl = try container.decodeIfPresent(String.self, forKey: .coverUrl)
        coverSize = try container.decodeIfPresent(Int.self, forKey: .coverSize)
        description = try container.decodeIfPresent(String.self, forKey: .description)
        scenicSpotId = try container.decodeIfPresent(Int.self, forKey: .scenicSpotId)
        scenicAreaId = try container.decodeIfPresent(Int.self, forKey: .scenicAreaId)
        uploaderId = try container.decodeIfPresent(Int.self, forKey: .uploaderId)
        status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
        likesCount = try container.decodeIfPresent(Int.self, forKey: .likesCount) ?? 0
        downloadCount = try container.decodeIfPresent(Int.self, forKey: .downloadCount) ?? 0
        collectCount = try container.decodeIfPresent(Int.self, forKey: .collectCount) ?? 0
        createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt)
        updatedAt = try container.decodeIfPresent(String.self, forKey: .updatedAt)
        deletedAt = try container.decodeIfPresent(String.self, forKey: .deletedAt)
        listingStatus = try container.decodeIfPresent(Int.self, forKey: .listingStatus) ?? 0
        reviewNotes = try container.decodeIfPresent(String.self, forKey: .reviewNotes)
        reviewTime = try container.decodeIfPresent(String.self, forKey: .reviewTime)
        reviewerId = try container.decodeIfPresent(Int.self, forKey: .reviewerId)
        provinceId = try container.decodeIfPresent(Int.self, forKey: .provinceId)
        cityId = try container.decodeIfPresent(Int.self, forKey: .cityId)
        shareCount = try container.decodeIfPresent(Int.self, forKey: .shareCount) ?? 0
        uploaderName = try container.decodeIfPresent(String.self, forKey: .uploaderName)
        uploaderAvatar = try container.decodeIfPresent(String.self, forKey: .uploaderAvatar)
        uploaderDescription = try container.decodeIfPresent(String.self, forKey: .uploaderDescription)
        platformCertification = try container.decodeIfPresent(Bool.self, forKey: .platformCertification) ?? false
        scenicCertification = try container.decodeIfPresent(Bool.self, forKey: .scenicCertification) ?? false
        mediaList = try container.decodeIfPresent([SampleDetailMediaItem].self, forKey: .mediaList)
        scenicName = try container.decodeIfPresent(String.self, forKey: .scenicName)
        scenicCoverImg = try container.decodeIfPresent(String.self, forKey: .scenicCoverImg)
        scenicPlanesNum = try container.decodeIfPresent(Int.self, forKey: .scenicPlanesNum) ?? 0
        scenicPhotographerNum = try container.decodeIfPresent(Int.self, forKey: .scenicPhotographerNum) ?? 0
        projectCover = try container.decodeIfPresent(String.self, forKey: .projectCover)
        projectName = try container.decodeIfPresent(String.self, forKey: .projectName)
        projectPrice = try container.decodeFlexibleDouble(forKey: .projectPrice)
        projectPriceDeposit = try container.decodeFlexibleString(forKey: .projectPriceDeposit)
        reviewer = try container.decodeIfPresent(String.self, forKey: .reviewer)
    }
}

/// 样片详情媒体项，对齐 Android `MaterialDetailMediaItem`。
struct SampleDetailMediaItem: Decodable, Sendable, Equatable, Hashable, Identifiable {
    let id: Int
    let originalName: String?
    let paidMaterialId: Int?
    let ossUrl: String?
    let thumbnailUrl: String?
    let type: Int
    let size: Int64?
    let createdAt: String?
    let updatedAt: String?
    let deletedAt: String?
    let likesCount: Int
    let downloadCount: Int
    let showUrl: String?
    let width: Int?
    let height: Int?

    enum CodingKeys: String, CodingKey {
        case id
        case originalName = "original_name"
        case paidMaterialId = "paid_material_id"
        case ossUrl = "oss_url"
        case thumbnailUrl = "thumbnail_url"
        case type
        case size
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case deletedAt = "deleted_at"
        case likesCount = "likes_count"
        case downloadCount = "download_count"
        case showUrl = "show_url"
        case width
        case height
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
        originalName = try container.decodeIfPresent(String.self, forKey: .originalName)
        paidMaterialId = try container.decodeIfPresent(Int.self, forKey: .paidMaterialId)
        ossUrl = try container.decodeIfPresent(String.self, forKey: .ossUrl)
        thumbnailUrl = try container.decodeIfPresent(String.self, forKey: .thumbnailUrl)
        type = try container.decodeIfPresent(Int.self, forKey: .type) ?? 0
        if let numericSize = try? container.decode(Int64.self, forKey: .size) {
            size = numericSize
        } else if let stringSize = try? container.decode(String.self, forKey: .size) {
            size = Int64(stringSize)
        } else {
            size = nil
        }
        createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt)
        updatedAt = try container.decodeIfPresent(String.self, forKey: .updatedAt)
        deletedAt = try container.decodeIfPresent(String.self, forKey: .deletedAt)
        likesCount = try container.decodeIfPresent(Int.self, forKey: .likesCount) ?? 0
        downloadCount = try container.decodeIfPresent(Int.self, forKey: .downloadCount) ?? 0
        showUrl = try container.decodeIfPresent(String.self, forKey: .showUrl)
        width = try container.decodeIfPresent(Int.self, forKey: .width)
        height = try container.decodeIfPresent(Int.self, forKey: .height)
    }

    /// 详情轮播优先展示地址。
    var displayURL: String {
        (ossUrl?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty)
            ?? (showUrl?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty)
            ?? ""
    }

    /// 返回可展示的媒体类型；服务端媒体项为 0 时按 Android 规则回退到详情顶层类型。
    func resolvedType(fallback: Int) -> Int {
        type == 0 ? fallback : type
    }
}

/// 样片关联项目项，对齐 Android `ProjectItem`。
struct SampleProjectItem: Decodable, Sendable, Equatable, Hashable, Identifiable {
    let id: Int
    let type: Int
    let typeName: String
    let status: Int
    let statusName: String
    let name: String
    let coverProject: String
    let coverVideo: String
    let price: String
    let otPrice: String
    let priceDeposit: String
    let label: String
    let attrLabel: [String]?
    let creatorId: Int

    enum CodingKeys: String, CodingKey {
        case id
        case type
        case typeName = "type_name"
        case status
        case statusName = "status_name"
        case name
        case coverProject = "cover_project"
        case coverVideo = "cover_video"
        case price
        case otPrice = "ot_price"
        case priceDeposit = "price_deposit"
        case label
        case attrLabel = "attr_label"
        case creatorId = "creator_id"
    }

    init(
        id: Int = 0,
        type: Int = 0,
        typeName: String = "",
        status: Int = 0,
        statusName: String = "",
        name: String = "",
        coverProject: String = "",
        coverVideo: String = "",
        price: String = "",
        otPrice: String = "",
        priceDeposit: String = "",
        label: String = "",
        attrLabel: [String]? = nil,
        creatorId: Int = 0
    ) {
        self.id = id
        self.type = type
        self.typeName = typeName
        self.status = status
        self.statusName = statusName
        self.name = name
        self.coverProject = coverProject
        self.coverVideo = coverVideo
        self.price = price
        self.otPrice = otPrice
        self.priceDeposit = priceDeposit
        self.label = label
        self.attrLabel = attrLabel
        self.creatorId = creatorId
    }
}

/// 样片关联项目分页响应，对齐 Android `ProjectListData`。
struct SampleProjectListResponse: Decodable, Sendable, Equatable {
    let list: [SampleProjectItem]
    let total: Int

    init(list: [SampleProjectItem] = [], total: Int = 0) {
        self.list = list
        self.total = total
    }
}

/// 样片上传请求，对齐 Android `UploadMaterialRequest`。
struct SampleUploadMaterialRequest: Encodable, Sendable, Equatable {
    let name: String
    let type: String
    let mediaType: String
    let mediaList: [SampleUploadMediaItem]
    let coverUrl: String
    let coverSize: String
    let scenicSpotId: Int64
    let description: String
    let materialTag: String
    let projectId: Int?

    enum CodingKeys: String, CodingKey {
        case name
        case type
        case mediaType = "media_type"
        case mediaList = "media_list"
        case coverUrl = "cover_url"
        case coverSize = "cover_size"
        case scenicSpotId = "scenic_spot_id"
        case description
        case materialTag = "material_tag"
        case projectId = "project_id"
    }

    init(
        name: String,
        mediaType: SampleMediaType,
        mediaList: [SampleUploadMediaItem],
        coverUrl: String,
        coverSize: String,
        scenicSpotId: Int64,
        projectId: Int?
    ) {
        self.name = name
        self.type = "2"
        self.mediaType = String(mediaType.rawValue)
        self.mediaList = mediaList
        self.coverUrl = coverUrl
        self.coverSize = coverSize
        self.scenicSpotId = scenicSpotId
        self.description = ""
        self.materialTag = ""
        self.projectId = projectId
    }
}

/// 样片上传素材项，对齐 Android `MediaItem`。
struct SampleUploadMediaItem: Encodable, Sendable, Equatable {
    let originalName: String
    let ossUrl: String
    let size: Int64
    let fileWidthSize: SampleUploadFileSize

    enum CodingKeys: String, CodingKey {
        case originalName = "original_name"
        case ossUrl = "oss_url"
        case size
        case fileWidthSize = "file_width_size"
    }
}

/// 样片上传文件宽高，对齐 Android `FileSize`。
struct SampleUploadFileSize: Encodable, Sendable, Equatable {
    let width: Int
    let height: Int
}

/// 上传页本地媒体项，不依赖 UIKit，供 ViewModel 管理上传状态。
struct SampleUploadedMediaItem: Sendable, Equatable, Hashable, Identifiable {
    let id: String
    let data: Data
    let thumbnailData: Data?
    let fileName: String
    let size: Int64
    let width: Int
    let height: Int
    var ossUrl: String
    var isUploading: Bool
    var uploadProgress: Int

    init(
        id: String = UUID().uuidString,
        data: Data,
        thumbnailData: Data? = nil,
        fileName: String,
        size: Int64? = nil,
        width: Int = 0,
        height: Int = 0,
        ossUrl: String = "",
        isUploading: Bool = false,
        uploadProgress: Int = 0
    ) {
        self.id = id
        self.data = data
        self.thumbnailData = thumbnailData
        self.fileName = fileName
        self.size = size ?? Int64(data.count)
        self.width = width
        self.height = height
        self.ossUrl = ossUrl
        self.isUploading = isUploading
        self.uploadProgress = uploadProgress
    }
}

/// 样片上传进度弹窗状态。
struct SampleUploadDialogState: Sendable, Equatable {
    let title: String
    let progress: Int
}

/// 样片 UI 展示格式化工具。
enum SampleDisplayFormatter {
    /// 格式化计数，超过 1000 按 Android 规则显示 k。
    static func formatCount(_ count: Int) -> String {
        guard count >= 1000 else { return String(count) }
        let value = Double(count) / 1000.0
        if value.truncatingRemainder(dividingBy: 1) == 0 {
            return "\(Int(value))k"
        }
        return String(format: "%.1fk", value)
    }

    /// 审核状态文案。
    static func reviewStatusText(_ status: Int) -> String {
        switch status {
        case 1: "已通过"
        case 0: "待审核"
        case 2: "未通过"
        default: "未知"
        }
    }
}

private extension KeyedDecodingContainer {
    func decodeFlexibleDouble(forKey key: Key) throws -> Double? {
        if let value = try? decode(Double.self, forKey: key) {
            return value
        }
        if let string = try? decode(String.self, forKey: key) {
            return Double(string)
        }
        return nil
    }

    func decodeFlexibleString(forKey key: Key) throws -> String? {
        if let value = try? decode(String.self, forKey: key) {
            return value
        }
        if let value = try? decode(Double.self, forKey: key) {
            return String(value)
        }
        if let value = try? decode(Int.self, forKey: key) {
            return String(value)
        }
        return nil
    }
}

private extension String {
    var nonEmpty: String? { isEmpty ? nil : self }
}
