//
//  TravelAlbumEntryViewModel.swift
//  suixinkan
//

import Foundation

/// 旅拍相册入口页 ViewModel，负责列表、创建相册和相册码状态。
final class TravelAlbumEntryViewModel {
    enum CreateMode: Int, Sendable {
        case preShoot = 0
        case preOrder = 1

        var apiType: Int {
            switch self {
            case .preShoot: 1
            case .preOrder: 2
            }
        }
    }

    /// 相册码弹窗状态。
    struct AlbumCodeState: Sendable, Equatable {
        let albumId: Int
        let albumName: String
        var qrImageUrl: String
        var isLoading: Bool
        var isDownloading: Bool
    }

    private(set) var albums: [TravelAlbum] = []
    private(set) var albumTotal = 0
    private(set) var availableOrders: [TravelAlbumAvailableOrder] = []
    private(set) var isLoading = false
    private(set) var isCreating = false
    private(set) var isCreateSheetVisible = false
    private(set) var albumCodeState: AlbumCodeState?

    var onStateChange: (() -> Void)?
    var onShowMessage: ((String) -> Void)?
    var onCreatedAlbum: ((TravelAlbumCreateResponse) -> Void)?

    private let currentScenicIdProvider: () -> Int
    private let dateProvider: () -> Date

    init(
        currentScenicIdProvider: @escaping () -> Int = { AppStore.shared.session.currentScenicId },
        dateProvider: @escaping () -> Date = Date.init
    ) {
        self.currentScenicIdProvider = currentScenicIdProvider
        self.dateProvider = dateProvider
    }

    /// 重新拉取相册列表。
    func loadAlbums(api: any TravelAlbumServing) async {
        isLoading = true
        notifyStateChange()
        defer {
            isLoading = false
            notifyStateChange()
        }

        do {
            let response = try await api.list(page: 1, pageSize: 20)
            albumTotal = response.total
            albums = response.list
        } catch is CancellationError {
            return
        } catch {
            albums = []
            albumTotal = 0
            onShowMessage?(error.localizedDescription)
        }
    }

    /// 打开创建相册弹窗。
    func openCreateSheet(api: any TravelAlbumServing) async {
        guard !isCreating else { return }
        guard currentScenicIdProvider() > 0 else {
            onShowMessage?("请先选择景区")
            return
        }
        isCreateSheetVisible = true
        notifyStateChange()
        await loadAvailableOrders(api: api)
    }

    /// 关闭创建相册弹窗。
    func dismissCreateSheet() {
        isCreateSheetVisible = false
        notifyStateChange()
    }

    /// 拉取可绑定订单。
    func loadAvailableOrders(api: any TravelAlbumServing) async {
        do {
            availableOrders = try await api.availableOrders()
            notifyStateChange()
        } catch is CancellationError {
            return
        } catch {
            availableOrders = []
            notifyStateChange()
        }
    }

    /// 校验并创建相册任务。
    func confirmCreate(
        mode: CreateMode,
        freeCount: String,
        singlePrice: String,
        packagePrice: String,
        order: TravelAlbumAvailableOrder?,
        api: any TravelAlbumServing
    ) async {
        guard !isCreating else { return }
        guard currentScenicIdProvider() > 0 else {
            onShowMessage?("请先选择景区")
            return
        }

        if mode == .preOrder && order == nil {
            onShowMessage?("请选择绑定订单")
            return
        }
        if mode == .preShoot && singlePrice.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            onShowMessage?("请输入单张照片价格")
            return
        }
        let materialPrice = Double(singlePrice)
        if mode == .preShoot && materialPrice == nil {
            onShowMessage?("请输入有效的单张照片价格")
            return
        }

        let albumName: String
        switch mode {
        case .preOrder:
            albumName = order?.projectName.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty ?? buildTodayAlbumName()
        case .preShoot:
            albumName = buildTodayAlbumName()
        }

        let request: TravelAlbumCreateRequest
        switch mode {
        case .preShoot:
            request = TravelAlbumCreateRequest(
                name: albumName,
                type: mode.apiType,
                orderNumber: nil,
                materialNum: Int(freeCount) ?? 0,
                materialPrice: materialPrice,
                materialPackagePrice: Double(packagePrice) ?? 0,
                photoPrice: 0
            )
        case .preOrder:
            request = TravelAlbumCreateRequest(
                name: albumName,
                type: mode.apiType,
                orderNumber: order?.orderNumber,
                materialNum: nil,
                materialPrice: nil,
                materialPackagePrice: nil,
                photoPrice: nil
            )
        }

        isCreating = true
        notifyStateChange()
        defer {
            isCreating = false
            notifyStateChange()
        }

        do {
            let response = try await api.create(request)
            isCreateSheetVisible = false
            onShowMessage?("任务创建成功")
            onCreatedAlbum?(response)
            await loadAlbums(api: api)
        } catch is CancellationError {
            return
        } catch {
            let message = error.localizedDescription
            if message.contains("订单已关联") {
                onShowMessage?("该订单已关联旅拍相册，请刷新后重新选择")
                await loadAvailableOrders(api: api)
            } else {
                onShowMessage?(message)
            }
        }
    }

    /// 打开相册码弹窗并加载二维码。
    func openAlbumCode(album: TravelAlbum, api: any TravelAlbumServing) async {
        albumCodeState = AlbumCodeState(
            albumId: album.id,
            albumName: album.name,
            qrImageUrl: "",
            isLoading: true,
            isDownloading: false
        )
        notifyStateChange()
        do {
            let response = try await api.mpCode(id: album.id)
            guard albumCodeState?.albumId == album.id else { return }
            albumCodeState?.qrImageUrl = response.mpCodeOssUrl.trimmingCharacters(in: .whitespacesAndNewlines)
            albumCodeState?.isLoading = false
            notifyStateChange()
        } catch is CancellationError {
            return
        } catch {
            guard albumCodeState?.albumId == album.id else { return }
            albumCodeState?.isLoading = false
            notifyStateChange()
            onShowMessage?(error.localizedDescription.isEmpty ? "获取小程序码失败" : error.localizedDescription)
        }
    }

    /// 关闭相册码弹窗。
    func dismissAlbumCode() {
        albumCodeState = nil
        notifyStateChange()
    }

    /// 设置二维码下载状态。
    func setDownloadingQRCode(_ isDownloading: Bool) {
        albumCodeState?.isDownloading = isDownloading
        notifyStateChange()
    }

    /// 生成 Android 同款今日相册名。
    func buildTodayAlbumName() -> String {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .gregorian)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd"
        let todayText = formatter.string(from: dateProvider())
        let todayCount = albums.filter { $0.createdAt.hasPrefix(todayText) }.count
        return "\(todayText)-\(String(format: "%03d", todayCount + 1))"
    }

    private func notifyStateChange() {
        onStateChange?()
    }
}

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