//
//  ScenicQueueAPI.swift
//  suixinkan
//

import Foundation

@MainActor
/// 排队管理 API 协议，便于 ViewModel 单元测试注入替身。
protocol ScenicQueueAPIProtocol {
    func saveSetting(_ request: ScenicQueueSaveSettingRequest) async throws
    func call(recordId: Int64) async throws -> ScenicQueueCallData
    func pass(recordId: Int64) async throws -> ScenicQueuePassData
    func finish(recordId: Int64) async throws -> ScenicQueueFinishData
    func userMark(_ request: ScenicQueueUserMarkRequest) async throws
    func requeueInsertBefore(recordId: Int64, operatorId: Int) async throws
    func shootQueueQrcode(scenicId: Int64, scenicSpotId: Int64) async throws -> ScenicQueueShootQueueQrcodeData
    func setting(scenicId: Int64?, scenicSpotId: Int64?) async throws -> ScenicQueueSettingData
    func stats(scenicId: Int64, scenicSpotId: Int64) async throws -> ScenicQueueStatsData
    func home(scenicId: Int64, scenicSpotId: Int64, type: Int, page: Int, pageSize: Int) async throws -> ScenicQueueHomeData
    func settingChangeLog(scenicId: Int64, scenicSpotId: Int64?, page: Int, pageSize: Int) async throws -> ScenicQueueSettingChangeLogData
    func scenicSpotListAll(scenicId: String) async throws -> ScenicSpotListResponse
    func socketToken() async throws -> SocketTokenResponse
    func aliyunSTS(bucket: String) async throws -> AliyunOSSResponse
}

@MainActor
/// 排队管理 API，封装 Android `NetworkApi` 中 scenic-queue 相关接口。
final class ScenicQueueAPI: ScenicQueueAPIProtocol {
    private let client: APIClient

    init(client: APIClient) {
        self.client = client
    }

    /// 保存排队设置。
    func saveSetting(_ request: ScenicQueueSaveSettingRequest) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(method: .post, path: "/api/app/scenic-queue/save-setting", body: request)
        )
    }

    /// 叫号。
    func call(recordId: Int64) async throws -> ScenicQueueCallData {
        try await client.send(
            APIRequest(method: .post, path: "/api/app/scenic-queue/call", body: ScenicQueueIdRequest(id: recordId))
        )
    }

    /// 过号。
    func pass(recordId: Int64) async throws -> ScenicQueuePassData {
        try await client.send(
            APIRequest(method: .post, path: "/api/app/scenic-queue/pass", body: ScenicQueueIdRequest(id: recordId))
        )
    }

    /// 完成拍摄。
    func finish(recordId: Int64) async throws -> ScenicQueueFinishData {
        try await client.send(
            APIRequest(method: .post, path: "/api/app/scenic-queue/finish", body: ScenicQueueIdRequest(id: recordId))
        )
    }

    /// 标记用户。
    func userMark(_ request: ScenicQueueUserMarkRequest) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(method: .post, path: "/api/app/scenic-queue/user-mark", body: request)
        )
    }

    /// 将过号记录插入队首后指定位置。
    func requeueInsertBefore(recordId: Int64, operatorId: Int) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/app/scenic-queue/requeue-insert-before",
                body: ScenicQueueRequeueInsertBeforeRequest(recordId: recordId, operatorId: operatorId)
            )
        )
    }

    /// 获取打卡点排队二维码。
    func shootQueueQrcode(scenicId: Int64, scenicSpotId: Int64) async throws -> ScenicQueueShootQueueQrcodeData {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/scenic-queue/shoot-queue-qrcode",
                queryItems: [
                    URLQueryItem(name: "scenic_id", value: String(scenicId)),
                    URLQueryItem(name: "scenic_spot_id", value: String(scenicSpotId)),
                ]
            )
        )
    }

    /// 获取指定打卡点设置。
    func setting(scenicId: Int64?, scenicSpotId: Int64?) async throws -> ScenicQueueSettingData {
        var items: [URLQueryItem] = []
        if let scenicId {
            items.append(URLQueryItem(name: "scenic_id", value: String(scenicId)))
        }
        if let scenicSpotId {
            items.append(URLQueryItem(name: "scenic_spot_id", value: String(scenicSpotId)))
        }
        return try await client.send(
            APIRequest(method: .get, path: "/api/app/scenic-queue/setting", queryItems: items)
        )
    }

    /// 获取排队统计。
    func stats(scenicId: Int64, scenicSpotId: Int64) async throws -> ScenicQueueStatsData {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/scenic-queue/queue-stats",
                queryItems: [
                    URLQueryItem(name: "scenic_id", value: String(scenicId)),
                    URLQueryItem(name: "scenic_spot_id", value: String(scenicSpotId)),
                ]
            )
        )
    }

    /// 获取排队首页列表。
    func home(scenicId: Int64, scenicSpotId: Int64, type: Int, page: Int, pageSize: Int) async throws -> ScenicQueueHomeData {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/scenic-queue/home",
                queryItems: [
                    URLQueryItem(name: "scenic_id", value: String(scenicId)),
                    URLQueryItem(name: "scenic_spot_id", value: String(scenicSpotId)),
                    URLQueryItem(name: "type", value: String(type)),
                    URLQueryItem(name: "page", value: String(page)),
                    URLQueryItem(name: "page_size", value: String(pageSize)),
                ]
            )
        )
    }

    /// 获取配置变更日志。
    func settingChangeLog(scenicId: Int64, scenicSpotId: Int64?, page: Int, pageSize: Int) async throws -> ScenicQueueSettingChangeLogData {
        var items = [
            URLQueryItem(name: "scenic_id", value: String(scenicId)),
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "page_size", value: String(pageSize)),
        ]
        if let scenicSpotId {
            items.append(URLQueryItem(name: "scenic_spot_id", value: String(scenicSpotId)))
        }
        return try await client.send(
            APIRequest(method: .get, path: "/api/app/scenic-queue/setting-change-log", queryItems: items)
        )
    }

    /// 获取当前景区全部打卡点。
    func scenicSpotListAll(scenicId: String) async throws -> ScenicSpotListResponse {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/yf-handset-app/photog/scenic-spot/list-all",
                queryItems: [URLQueryItem(name: "scenic_id", value: scenicId)]
            )
        )
    }

    /// 获取业务 WebSocket token。
    func socketToken() async throws -> SocketTokenResponse {
        try await client.send(APIRequest(method: .get, path: "/api/app/socket-token"))
    }

    /// 获取阿里云 STS 临时凭证。
    func aliyunSTS(bucket: String = "vipsky") async throws -> AliyunOSSResponse {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/config/get-sts-token",
                queryItems: [URLQueryItem(name: "bucket", value: bucket)]
            )
        )
    }
}

/// 仅包含 id 的排队操作请求体。
struct ScenicQueueIdRequest: Encodable, Equatable {
    let id: Int64
}

/// 过号重排请求体。
struct ScenicQueueRequeueInsertBeforeRequest: Encodable, Equatable {
    let recordId: Int64
    let operatorId: Int

    enum CodingKeys: String, CodingKey {
        case recordId = "record_id"
        case operatorId = "operator_id"
    }
}

/// 用户标记请求体。
struct ScenicQueueUserMarkRequest: Encodable, Equatable {
    let uid: Int64
    let scenicId: Int64
    let markAsFreelancePhotog: Int
    let queueBanDays: Int?
    let operatorId: Int?

    enum CodingKeys: String, CodingKey {
        case uid
        case scenicId = "scenic_id"
        case markAsFreelancePhotog = "mark_as_freelance_photog"
        case queueBanDays = "queue_ban_days"
        case operatorId = "operator_id"
    }
}
