//
//  OrdersAPI.swift
//  suixinkan
//
//  Created by Codex on 2026/6/22.
//

import Foundation
import Combine

@MainActor
/// 订单服务协议，抽象订单列表、核销列表和核销操作以便测试替换。
protocol OrderServing {
    /// 获取订单管理列表。
    func orderList(
        scenicId: Int,
        page: Int,
        pageSize: Int,
        orderStatus: Int?,
        userPhone: String?,
        startTime: String?,
        endTime: String?,
        isRefined: Int?,
        isScenicAdmin: Bool
    ) async throws -> ListPayload<OrderEntity>

    /// 获取核销订单列表。
    func writeOffList(
        scenicId: Int,
        storeId: Int?,
        page: Int,
        pageSize: Int,
        orderStatus: Int?,
        orderVerifyStatus: Int?,
        startTime: String?,
        endTime: String?,
        userPhone: String?
    ) async throws -> ListPayload<WriteOffOrderItem>

    /// 核销指定订单号。
    func writeOff(orderNumber: String) async throws

    /// 更新订单精修选择。
    func updateRefinedChoice(orderNumber: String, isRefined: Int) async throws

    /// 取消订单。
    func cancelOrder(orderNumber: String) async throws

    /// 赠送修图/视频数量。
    func sendGift(orderNumber: String, photoNum: Int, videoNum: Int) async throws

    /// 获取店长店铺订单列表。
    func storeOrderList(
        storeId: Int?,
        page: Int,
        pageSize: Int,
        userPhone: String?,
        orderStatus: Int?,
        orderType: Int?,
        startTime: String?,
        endTime: String?
    ) async throws -> ListPayload<StoreOrderListItem>

    /// 申请店长店铺订单退款。
    func storeOrderRefund(
        storeId: Int,
        orderNumber: String,
        refundType: OrderRefundMode,
        refundAmount: String,
        refundReason: String
    ) async throws

    /// 获取门店订单详情。
    func storeOrderDetail(storeId: Int, orderNumber: String) async throws -> StoreOrderDetailResponse

    /// 获取押金订单列表。
    func depositOrderList(scenicId: Int, page: Int, pageSize: Int) async throws -> ListPayload<DepositOrderListItem>

    /// 核销押金订单。
    func depositOrderWriteOff(orderNumber: String) async throws

    /// 申请押金订单退款。
    func depositOrderRefund(orderNumber: String, refundReason: String) async throws

    /// 获取订单某个拍摄点的底片、成片和评价信息。
    func storeOrderShootingDetail(storeId: Int, orderNumber: String, scenicSpotId: Int, photogUid: Int) async throws -> StoreOrderShootingDetailResponse

    /// 申请普通订单退款。
    func orderRefund(orderNumber: String, refundType: OrderRefundMode, refundAmount: String, refundReason: String) async throws

    /// 获取订单历史拍摄信息。
    func multiTravelShootHistory(orderNumber: String) async throws -> MultiTravelShootHistoryResponse

    /// 获取多点旅拍订单已核销打卡点列表。
    func multiTravelVerifiedScenicSpotList(orderNumber: String) async throws -> [MultiTravelVerifiedScenicSpotItem]

    /// 提交多点旅拍任务素材。
    func multiTravelUploadMaterial(_ request: MultiTravelUploadMaterialRequest) async throws
}

@MainActor
/// 订单 API，封装订单管理、核销订单和订单核销接口。
final class OrdersAPI: OrderServing {
    private let client: APIClient

    /// 初始化订单 API，并注入共享网络客户端。
    init(client: APIClient) {
        self.client = client
    }

    /// 获取订单管理列表。
    func orderList(
        scenicId: Int,
        page: Int = 1,
        pageSize: Int = 20,
        orderStatus: Int? = nil,
        userPhone: String? = nil,
        startTime: String? = nil,
        endTime: String? = nil,
        isRefined: Int? = nil,
        isScenicAdmin: Bool = false
    ) async throws -> ListPayload<OrderEntity> {
        var query = [
            URLQueryItem(name: "scenic_id", value: "\(scenicId)"),
            URLQueryItem(name: "page", value: "\(max(page, 1))"),
            URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))")
        ]
        if let orderStatus, orderStatus > 0 {
            query.append(URLQueryItem(name: "order_status", value: "\(orderStatus)"))
        }
        if let userPhone, !userPhone.isEmpty {
            query.append(URLQueryItem(name: "user_phone", value: userPhone))
        }
        if let startTime, !startTime.isEmpty {
            query.append(URLQueryItem(name: "start_time", value: startTime))
        }
        if let endTime, !endTime.isEmpty {
            query.append(URLQueryItem(name: "end_time", value: endTime))
        }
        if let isRefined, isRefined > 0 {
            query.append(URLQueryItem(name: "is_refined", value: "\(isRefined)"))
        }

        return try await client.send(
            APIRequest(
                method: .get,
                path: isScenicAdmin ? "/api/app/scenic-admin/order/list" : "/api/yf-handset-app/photog/order/listv2",
                queryItems: query
            )
        )
    }

    /// 获取核销订单列表。
    func writeOffList(
        scenicId: Int,
        storeId: Int? = nil,
        page: Int = 1,
        pageSize: Int = 20,
        orderStatus: Int? = nil,
        orderVerifyStatus: Int? = nil,
        startTime: String? = nil,
        endTime: String? = nil,
        userPhone: String? = nil
    ) async throws -> ListPayload<WriteOffOrderItem> {
        var queryItems = [
            URLQueryItem(name: "scenic_id", value: "\(scenicId)"),
            URLQueryItem(name: "page", value: "\(max(page, 1))"),
            URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))")
        ]
        if let storeId, storeId > 0 {
            queryItems.append(URLQueryItem(name: "store_id", value: "\(storeId)"))
        }
        if let orderStatus, orderStatus > 0 {
            queryItems.append(URLQueryItem(name: "order_status", value: "\(orderStatus)"))
        }
        if let orderVerifyStatus, orderVerifyStatus > 0 {
            queryItems.append(URLQueryItem(name: "order_verify_status", value: "\(orderVerifyStatus)"))
        }
        if let startTime, !startTime.isEmpty {
            queryItems.append(URLQueryItem(name: "start_time", value: startTime))
        }
        if let endTime, !endTime.isEmpty {
            queryItems.append(URLQueryItem(name: "end_time", value: endTime))
        }
        if let userPhone, !userPhone.isEmpty {
            queryItems.append(URLQueryItem(name: "user_phone", value: userPhone))
        }

        return try await client.send(
            APIRequest(
                method: .get,
                path: "/api/yf-handset-app/photog/order/order-verification-list",
                queryItems: queryItems
            )
        )
    }

    /// 核销指定订单号。
    func writeOff(orderNumber: String) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/order-verify",
                body: WriteOffRequest(orderNumber: orderNumber)
            )
        )
    }

    /// 获取门店订单详情。
    func storeOrderDetail(storeId: Int, orderNumber: String) async throws -> StoreOrderDetailResponse {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/store/order/detail",
                queryItems: [
                    URLQueryItem(name: "store_id", value: "\(storeId)"),
                    URLQueryItem(name: "order_number", value: orderNumber)
                ]
            )
        )
    }

    /// 获取押金订单列表。
    func depositOrderList(scenicId: Int, page: Int = 1, pageSize: Int = 10) async throws -> ListPayload<DepositOrderListItem> {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/yf-handset-app/photog/order/deposit-list",
                queryItems: [
                    URLQueryItem(name: "scenic_id", value: "\(scenicId)"),
                    URLQueryItem(name: "page", value: "\(max(page, 1))"),
                    URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))")
                ]
            )
        )
    }

    /// 核销押金订单。
    func depositOrderWriteOff(orderNumber: String) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/deposit-writeoff",
                body: DepositOrderWriteOffRequest(orderNumber: orderNumber)
            )
        )
    }

    /// 申请押金订单退款。
    func depositOrderRefund(orderNumber: String, refundReason: String) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/deposit-refund",
                body: DepositOrderRefundRequest(orderNumber: orderNumber, refundReason: refundReason)
            )
        )
    }

    /// 获取订单某个拍摄点的底片、成片和评价信息。
    func storeOrderShootingDetail(storeId: Int, orderNumber: String, scenicSpotId: Int, photogUid: Int) async throws -> StoreOrderShootingDetailResponse {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/store/order/shooting-detail",
                queryItems: [
                    URLQueryItem(name: "store_id", value: "\(storeId)"),
                    URLQueryItem(name: "order_number", value: orderNumber),
                    URLQueryItem(name: "scenic_spot_id", value: "\(scenicSpotId)"),
                    URLQueryItem(name: "photog_uid", value: "\(photogUid)")
                ]
            )
        )
    }

    /// 申请普通订单退款。
    func orderRefund(orderNumber: String, refundType: OrderRefundMode, refundAmount: String, refundReason: String) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/refund",
                body: OrderRefundRequest(
                    orderNumber: orderNumber,
                    refundType: refundType.rawValue,
                    refundAmount: refundAmount,
                    refundReason: refundReason
                )
            )
        )
    }

    /// 获取订单历史拍摄信息。
    func multiTravelShootHistory(orderNumber: String) async throws -> MultiTravelShootHistoryResponse {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/yf-handset-app/photog/order/multi-travel/shoot-history",
                queryItems: [URLQueryItem(name: "order_number", value: orderNumber)]
            )
        )
    }

    /// 获取多点旅拍订单已核销打卡点列表。
    func multiTravelVerifiedScenicSpotList(orderNumber: String) async throws -> [MultiTravelVerifiedScenicSpotItem] {
        try await client.send(
            APIRequest(
                method: .get,
                path: "/api/yf-handset-app/photog/order/multi-travel/verified-scenic-spot-list",
                queryItems: [URLQueryItem(name: "order_number", value: orderNumber)]
            )
        )
    }

    /// 提交多点旅拍任务素材。
    func multiTravelUploadMaterial(_ request: MultiTravelUploadMaterialRequest) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/multi-travel/upload-material",
                body: request
            )
        )
    }

    /// 更新订单精修选择。
    func updateRefinedChoice(orderNumber: String, isRefined: Int) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/refined",
                queryItems: [
                    URLQueryItem(name: "order_number", value: orderNumber),
                    URLQueryItem(name: "is_refined", value: "\(isRefined)")
                ]
            )
        )
    }

    /// 取消订单。
    func cancelOrder(orderNumber: String) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/cancel",
                body: CancelOrderRequest(orderNumber: orderNumber)
            )
        )
    }

    /// 赠送修图/视频数量。
    func sendGift(orderNumber: String, photoNum: Int, videoNum: Int) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/yf-handset-app/photog/order/gift-retouch",
                body: SendGiftRequest(orderNumber: orderNumber, photoNum: photoNum, videoNum: videoNum)
            )
        )
    }

    /// 获取店长店铺订单列表。
    func storeOrderList(
        storeId: Int? = nil,
        page: Int = 1,
        pageSize: Int = 20,
        userPhone: String? = nil,
        orderStatus: Int? = nil,
        orderType: Int? = nil,
        startTime: String? = nil,
        endTime: String? = nil
    ) async throws -> ListPayload<StoreOrderListItem> {
        var queryItems = [
            URLQueryItem(name: "page", value: "\(max(page, 1))"),
            URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))")
        ]
        if let storeId, storeId > 0 {
            queryItems.append(URLQueryItem(name: "store_id", value: "\(storeId)"))
        }
        if let userPhone, !userPhone.isEmpty {
            queryItems.append(URLQueryItem(name: "user_phone", value: userPhone))
        }
        if let orderStatus, orderStatus > 0 {
            queryItems.append(URLQueryItem(name: "order_status", value: "\(orderStatus)"))
        }
        if let orderType {
            queryItems.append(URLQueryItem(name: "order_type", value: "\(orderType)"))
        }
        if let startTime, !startTime.isEmpty {
            queryItems.append(URLQueryItem(name: "start_time", value: startTime))
        }
        if let endTime, !endTime.isEmpty {
            queryItems.append(URLQueryItem(name: "end_time", value: endTime))
        }

        return try await client.send(
            APIRequest(
                method: .get,
                path: "/api/app/store/order/list",
                queryItems: queryItems
            )
        )
    }

    /// 申请店长店铺订单退款。
    func storeOrderRefund(
        storeId: Int,
        orderNumber: String,
        refundType: OrderRefundMode,
        refundAmount: String,
        refundReason: String
    ) async throws {
        let _: EmptyPayload = try await client.send(
            APIRequest(
                method: .post,
                path: "/api/app/store/order/refund",
                body: StoreOrderRefundRequest(
                    storeId: storeId,
                    orderNumber: orderNumber,
                    refundType: refundType.rawValue,
                    refundAmount: refundAmount,
                    refundReason: refundReason
                )
            )
        )
    }
}
