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

import Foundation

/// 直播列表响应实体。
struct LiveListResponse: Decodable {
    let items: [LiveEntity]
    let total: Int
    let page: Int
    let pageSize: Int

    enum CodingKeys: String, CodingKey {
        case items
        case total
        case page
        case pageSize = "page_size"
    }

    init(items: [LiveEntity] = [], total: Int = 0, page: Int = 1, pageSize: Int = 10) {
        self.items = items
        self.total = total
        self.page = page
        self.pageSize = pageSize
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        items = (try? container.decode([LiveEntity].self, forKey: .items)) ?? []
        total = try container.liveDecodeLossyInt(forKey: .total) ?? 0
        page = try container.liveDecodeLossyInt(forKey: .page) ?? 1
        pageSize = try container.liveDecodeLossyInt(forKey: .pageSize) ?? 10
    }
}

/// 直播实体，表示一场手动直播。
struct LiveEntity: Decodable, Identifiable, Equatable {
    let id: Int
    let title: String
    let coverImg: String
    let pushUrl: String
    let playUrl: String
    let pullUrl: String
    let hlsUrl: String
    let flvUrl: String
    let liveUrl: String
    let startTime: Int64
    let endTime: Int64
    let duration: Int64
    let status: Int
    let statusLabel: String
    let manualPushMode: Int
    let manualPushState: Int
    let viewsCount: Int

    enum CodingKeys: String, CodingKey {
        case id
        case title
        case coverImg = "cover_img"
        case pushUrl = "push_url"
        case playUrl = "play_url"
        case pullUrl = "pull_url"
        case hlsUrl = "hls_url"
        case flvUrl = "flv_url"
        case liveUrl = "live_url"
        case startTime = "start_time"
        case endTime = "end_time"
        case duration
        case status
        case statusLabel = "status_label"
        case manualPushMode = "manaul_push_mode"
        case manualPushState = "manaul_push_state"
        case viewsCount = "views_count"
    }

    init(
        id: Int = 0,
        title: String = "",
        coverImg: String = "",
        pushUrl: String = "",
        playUrl: String = "",
        pullUrl: String = "",
        hlsUrl: String = "",
        flvUrl: String = "",
        liveUrl: String = "",
        startTime: Int64 = 0,
        endTime: Int64 = 0,
        duration: Int64 = 0,
        status: Int = 0,
        statusLabel: String = "",
        manualPushMode: Int = 1,
        manualPushState: Int = 0,
        viewsCount: Int = 0
    ) {
        self.id = id
        self.title = title
        self.coverImg = coverImg
        self.pushUrl = pushUrl
        self.playUrl = playUrl
        self.pullUrl = pullUrl
        self.hlsUrl = hlsUrl
        self.flvUrl = flvUrl
        self.liveUrl = liveUrl
        self.startTime = startTime
        self.endTime = endTime
        self.duration = duration
        self.status = status
        self.statusLabel = statusLabel
        self.manualPushMode = manualPushMode
        self.manualPushState = manualPushState
        self.viewsCount = viewsCount
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.liveDecodeLossyInt(forKey: .id) ?? 0
        title = try container.liveDecodeLossyString(forKey: .title)
        coverImg = try container.liveDecodeLossyString(forKey: .coverImg)
        pushUrl = try container.liveDecodeLossyString(forKey: .pushUrl)
        playUrl = try container.liveDecodeLossyString(forKey: .playUrl)
        pullUrl = try container.liveDecodeLossyString(forKey: .pullUrl)
        hlsUrl = try container.liveDecodeLossyString(forKey: .hlsUrl)
        flvUrl = try container.liveDecodeLossyString(forKey: .flvUrl)
        liveUrl = try container.liveDecodeLossyString(forKey: .liveUrl)
        startTime = Int64(try container.liveDecodeLossyInt(forKey: .startTime) ?? 0)
        endTime = Int64(try container.liveDecodeLossyInt(forKey: .endTime) ?? 0)
        duration = Int64(try container.liveDecodeLossyInt(forKey: .duration) ?? 0)
        status = try container.liveDecodeLossyInt(forKey: .status) ?? 0
        statusLabel = try container.liveDecodeLossyString(forKey: .statusLabel)
        manualPushMode = try container.liveDecodeLossyInt(forKey: .manualPushMode) ?? 1
        manualPushState = try container.liveDecodeLossyInt(forKey: .manualPushState) ?? 0
        viewsCount = try container.liveDecodeLossyInt(forKey: .viewsCount) ?? 0
    }

    var displayStatus: String {
        statusLabel.liveNonEmpty ?? "状态\(status)"
    }

    var playbackURLCandidates: [String] {
        [playUrl, pullUrl, hlsUrl, liveUrl, flvUrl]
    }
}

/// 创建直播请求实体。
struct LiveCreateRequest: Encodable, Equatable {
    let scenicId: String
    let title: String
    let coverImg: String

    enum CodingKeys: String, CodingKey {
        case scenicId = "scenic_id"
        case title
        case coverImg = "cover_img"
    }
}

/// 直播控制请求实体。
struct LiveControlRequest: Encodable, Equatable {
    let liveId: Int

    enum CodingKeys: String, CodingKey {
        case liveId = "live_id"
    }
}

/// 直播推流模式切换请求实体。
struct LivePushModeRequest: Encodable, Equatable {
    let liveId: Int
    let manualPushMode: Int

    enum CodingKeys: String, CodingKey {
        case liveId = "live_id"
        case manualPushMode = "manual_push_mode"
    }
}

/// 直播相册列表响应实体。
struct LiveAlbumFolderListResponse: Decodable {
    let items: [LiveAlbumFolderItem]
    let page: Int
    let pageSize: Int
    let total: Int
    let totalPages: Int

    enum CodingKeys: String, CodingKey {
        case items
        case page
        case pageSize = "page_size"
        case total
        case totalPages = "total_pages"
    }

    init(items: [LiveAlbumFolderItem] = [], page: Int = 1, pageSize: Int = 10, total: Int = 0, totalPages: Int = 0) {
        self.items = items
        self.page = page
        self.pageSize = pageSize
        self.total = total
        self.totalPages = totalPages
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        items = (try? container.decode([LiveAlbumFolderItem].self, forKey: .items)) ?? []
        page = try container.liveDecodeLossyInt(forKey: .page) ?? 1
        pageSize = try container.liveDecodeLossyInt(forKey: .pageSize) ?? 10
        total = try container.liveDecodeLossyInt(forKey: .total) ?? 0
        totalPages = try container.liveDecodeLossyInt(forKey: .totalPages) ?? 0
    }
}

/// 直播相册文件夹实体。
struct LiveAlbumFolderItem: Decodable, Identifiable, Equatable {
    let id: Int
    let albumId: Int
    let name: String
    let creator: String
    let items: [LiveAlbumFileItem]

    enum CodingKeys: String, CodingKey {
        case id
        case albumId = "album_id"
        case name
        case creator
        case items
    }

    init(id: Int = 0, albumId: Int = 0, name: String = "", creator: String = "", items: [LiveAlbumFileItem] = []) {
        self.id = id
        self.albumId = albumId
        self.name = name
        self.creator = creator
        self.items = items
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.liveDecodeLossyInt(forKey: .id) ?? 0
        albumId = try container.liveDecodeLossyInt(forKey: .albumId) ?? 0
        name = try container.liveDecodeLossyString(forKey: .name)
        creator = try container.liveDecodeLossyString(forKey: .creator)
        items = (try? container.decode([LiveAlbumFileItem].self, forKey: .items)) ?? []
    }
}

/// 直播相册素材实体。
struct LiveAlbumFileItem: Decodable, Identifiable, Hashable {
    let id: Int
    let url: String
    let type: Int
    let size: Int64
    let coverImg: String?

    enum CodingKeys: String, CodingKey {
        case id
        case url
        case type
        case size
        case coverImg = "cover_img"
    }

    init(id: Int = 0, url: String = "", type: Int = 1, size: Int64 = 0, coverImg: String? = nil) {
        self.id = id
        self.url = url
        self.type = type
        self.size = size
        self.coverImg = coverImg
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.liveDecodeLossyInt(forKey: .id) ?? 0
        url = try container.liveDecodeLossyString(forKey: .url)
        type = try container.liveDecodeLossyInt(forKey: .type) ?? 1
        size = Int64(try container.liveDecodeLossyInt(forKey: .size) ?? 0)
        coverImg = try? container.decodeIfPresent(String.self, forKey: .coverImg)
    }

    var isVideo: Bool { type == 2 }

    var previewURL: String {
        if let cover = coverImg?.liveTrimmed, !cover.isEmpty {
            return cover
        }
        return url
    }
}

/// 创建直播相册请求实体。
struct LiveAlbumCreateFolderRequest: Encodable, Equatable {
    let scenicId: String
    let name: String
    let items: [LiveAlbumCreateFileItem]

    enum CodingKeys: String, CodingKey {
        case scenicId = "scenic_id"
        case name
        case items
    }
}

/// 创建直播相册素材请求实体。
struct LiveAlbumCreateFileItem: Encodable, Equatable {
    let url: String
    let type: Int
    let size: Int64
    let coverImg: String?

    enum CodingKeys: String, CodingKey {
        case url
        case type
        case size
        case coverImg = "cover_img"
    }
}

/// 删除直播相册请求实体。
struct LiveAlbumDeleteFolderRequest: Encodable, Equatable {
    let folderId: Int

    enum CodingKeys: String, CodingKey {
        case folderId = "folder_id"
    }
}

/// 删除直播相册素材请求实体。
struct LiveAlbumDeleteFilesRequest: Encodable, Equatable {
    let folderId: Int
    let fileIds: [Int]

    enum CodingKeys: String, CodingKey {
        case folderId = "folder_id"
        case fileIds = "file_ids"
    }
}

/// 本地待上传直播相册素材实体。
struct LiveAlbumLocalUploadFile: Identifiable, Equatable {
    let id: UUID
    let data: Data
    let fileName: String
    let fileType: Int
    let size: Int64
    var uploadedURL: String?

    init(id: UUID = UUID(), data: Data, fileName: String, fileType: Int, size: Int64? = nil, uploadedURL: String? = nil) {
        self.id = id
        self.data = data
        self.fileName = fileName
        self.fileType = fileType
        self.size = size ?? Int64(data.count)
        self.uploadedURL = uploadedURL
    }

    var isVideo: Bool { fileType == 2 }
}

private extension KeyedDecodingContainer {
    func liveDecodeLossyString(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(Int64.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 ""
    }

    func liveDecodeLossyInt(forKey key: Key) throws -> Int? {
        if let value = try? decodeIfPresent(Int.self, forKey: key) {
            return value
        }
        if let value = try? decodeIfPresent(Int64.self, forKey: key) {
            return Int(value)
        }
        if let value = try? decodeIfPresent(Double.self, forKey: key) {
            return Int(value)
        }
        if let value = try? decodeIfPresent(String.self, forKey: key) {
            let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
            if let intValue = Int(trimmed) {
                return intValue
            }
            if let doubleValue = Double(trimmed) {
                return Int(doubleValue)
            }
        }
        return nil
    }
}

extension String {
    /// 直播模块内部使用的去空白字符串。
    var liveTrimmed: String {
        trimmingCharacters(in: .whitespacesAndNewlines)
    }

    /// 直播模块内部使用的非空字符串兜底。
    var liveNonEmpty: String? {
        let value = liveTrimmed
        return value.isEmpty ? nil : value
    }
}
