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

import AVFoundation
import Photos
import SwiftUI

/// 收款页，展示静态收款码、动态金额收款和收款记录入口。
struct PaymentCollectionView: View {
    @Environment(AccountContext.self) private var accountContext
    @Environment(PaymentAPI.self) private var paymentAPI
    @Environment(ToastCenter.self) private var toastCenter
    @Environment(\.globalLoading) private var globalLoading

    @State private var viewModel = PaymentCollectionViewModel()
    @State private var showingAmountSheet = false
    @State private var pollingTask: Task<Void, Never>?
    @State private var speaker = PaymentVoiceSpeaker()

    var body: some View {
        ScrollView {
            VStack(spacing: AppMetrics.Spacing.medium) {
                contextHeader
                qrCard
                actionGrid
                statusCard
            }
            .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
            .padding(.vertical, AppMetrics.Spacing.pageVertical)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("立即收款")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                NavigationLink {
                    PaymentCollectionRecordView()
                } label: {
                    Image(systemName: "list.bullet.rectangle")
                }
            }
        }
        .task(id: accountContext.currentScenic?.id) {
            await globalLoading.withOptionalLoading(viewModel.qrImage == nil, message: "加载中...") {
                await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
            }
        }
        .sheet(isPresented: $showingAmountSheet) {
            amountSheet
                .presentationDetents([.medium])
        }
        .onDisappear {
            pollingTask?.cancel()
        }
        .onChange(of: viewModel.errorMessage) { _, message in
            if let message {
                toastCenter.show(message)
            }
        }
        .onChange(of: viewModel.status) { _, status in
            if case .success(let item) = status {
                speaker.speak("收款到账\(item.orderAmount)元")
            }
        }
    }

    /// 景区上下文展示区。
    private var contextHeader: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            Image(systemName: "mappin.and.ellipse")
                .foregroundStyle(AppDesign.primary)
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xxxSmall) {
                Text(accountContext.currentScenic?.name ?? "未选择景区")
                    .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                    .foregroundStyle(AppDesign.textPrimary)
                Text("收款记录按当前景区查询")
                    .font(.system(size: AppMetrics.FontSize.caption))
                    .foregroundStyle(AppDesign.textSecondary)
            }
            Spacer()
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: 8))
    }

    /// 二维码展示卡片。
    private var qrCard: some View {
        VStack(spacing: AppMetrics.Spacing.medium) {
            if let image = viewModel.qrImage {
                Image(uiImage: image)
                    .interpolation(.none)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 220, height: 220)
                    .background(.white)
            } else {
                VStack(spacing: AppMetrics.Spacing.small) {
                    Image(systemName: "qrcode")
                        .font(.system(size: 56, weight: .semibold))
                        .foregroundStyle(AppDesign.placeholder)
                    Text("暂无收款码")
                        .font(.system(size: AppMetrics.FontSize.subheadline))
                        .foregroundStyle(AppDesign.textSecondary)
                }
                .frame(width: 220, height: 220)
            }

            Text(viewModel.currentPayUrl.isEmpty ? "请先加载收款码" : "向客户展示二维码完成收款")
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.textSecondary)
                .multilineTextAlignment(.center)
        }
        .frame(maxWidth: .infinity)
        .padding(AppMetrics.Spacing.large)
        .background(.white, in: RoundedRectangle(cornerRadius: 8))
    }

    /// 收款操作按钮区。
    private var actionGrid: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            paymentActionButton(title: "设置金额", icon: "yensign.circle.fill") {
                showingAmountSheet = true
            }
            paymentActionButton(title: "保存二维码", icon: "square.and.arrow.down") {
                saveQRCode()
            }
            paymentActionButton(title: "刷新", icon: "arrow.clockwise") {
                Task {
                    await globalLoading.withLoading(message: "刷新中...") {
                        await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
                    }
                }
            }
        }
    }

    /// 当前收款状态展示卡。
    @ViewBuilder
    private var statusCard: some View {
        switch viewModel.status {
        case .idle:
            EmptyView()
        case .waiting:
            HStack(spacing: AppMetrics.Spacing.small) {
                ProgressView()
                Text("等待付款到账...")
                    .font(.system(size: AppMetrics.FontSize.subheadline, weight: .medium))
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(AppMetrics.Spacing.medium)
            .background(.white, in: RoundedRectangle(cornerRadius: 8))
        case .success(let item):
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xSmall) {
                Label("收款成功", systemImage: "checkmark.circle.fill")
                    .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                    .foregroundStyle(AppDesign.success)
                Text("订单号：\(item.orderNumber)")
                Text("金额：¥\(item.orderAmount)")
            }
            .font(.system(size: AppMetrics.FontSize.subheadline))
            .foregroundStyle(AppDesign.textPrimary)
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(AppMetrics.Spacing.medium)
            .background(.white, in: RoundedRectangle(cornerRadius: 8))
        case .failed(let message):
            Text(message)
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.warning)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(AppMetrics.Spacing.medium)
                .background(.white, in: RoundedRectangle(cornerRadius: 8))
        }
    }

    /// 设置金额弹窗。
    private var amountSheet: some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.medium) {
            Text("设置收款金额")
                .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
                .foregroundStyle(AppDesign.textPrimary)

            TextField("请输入金额", text: $viewModel.amountText)
                .keyboardType(.decimalPad)
                .appInputFieldStyle(cornerRadius: 8, minHeight: AppMetrics.ControlSize.inputHeight)

            TextField("备注，可不填", text: $viewModel.remarkText)
                .appInputFieldStyle(cornerRadius: 8, minHeight: AppMetrics.ControlSize.inputHeight)

            Button {
                if viewModel.applyDynamicAmount() {
                    showingAmountSheet = false
                    startPolling()
                } else if let message = viewModel.errorMessage {
                    toastCenter.show(message)
                }
            } label: {
                Text("生成动态二维码")
                    .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                    .frame(maxWidth: .infinity, minHeight: AppMetrics.ControlSize.primaryButtonHeight)
                    .foregroundStyle(.white)
                    .background(AppDesign.primary, in: RoundedRectangle(cornerRadius: 8))
            }
        }
        .padding(AppMetrics.Spacing.large)
    }

    /// 生成操作按钮。
    private func paymentActionButton(title: String, icon: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            VStack(spacing: AppMetrics.Spacing.xSmall) {
                Image(systemName: icon)
                    .font(.system(size: 22, weight: .semibold))
                Text(title)
                    .font(.system(size: AppMetrics.FontSize.footnote, weight: .medium))
            }
            .foregroundStyle(AppDesign.primary)
            .frame(maxWidth: .infinity, minHeight: 76)
            .background(.white, in: RoundedRectangle(cornerRadius: 8))
        }
    }

    /// 启动本次动态收款轮询。
    private func startPolling() {
        pollingTask?.cancel()
        pollingTask = Task {
            await viewModel.primePaymentRecords(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
            await viewModel.pollUntilPaymentDetected(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
        }
    }

    /// 保存当前二维码到系统相册。
    private func saveQRCode() {
        guard let image = viewModel.qrImage else {
            toastCenter.show("暂无可保存二维码")
            return
        }
        PHPhotoLibrary.requestAuthorization(for: .addOnly) { status in
            guard status == .authorized || status == .limited else {
                Task { @MainActor in toastCenter.show("请允许添加照片权限") }
                return
            }
            PHPhotoLibrary.shared().performChanges {
                PHAssetChangeRequest.creationRequestForAsset(from: image)
            } completionHandler: { success, error in
                Task { @MainActor in
                    toastCenter.show(success ? "二维码已保存" : (error?.localizedDescription ?? "保存失败"))
                }
            }
        }
    }
}

/// 收款记录页，按日期展示扫码收款明细。
struct PaymentCollectionRecordView: View {
    @Environment(AccountContext.self) private var accountContext
    @Environment(PaymentAPI.self) private var paymentAPI
    @Environment(ToastCenter.self) private var toastCenter
    @Environment(\.globalLoading) private var globalLoading
    @State private var viewModel = PaymentCollectionRecordViewModel()

    var body: some View {
        List {
            ForEach(viewModel.groups) { group in
                Section {
                    ForEach(group.items) { item in
                        VStack(alignment: .leading, spacing: AppMetrics.Spacing.xxSmall) {
                            HStack {
                                Text("¥\(item.orderAmount)")
                                    .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                                Spacer()
                                Text(item.createTime)
                                    .font(.system(size: AppMetrics.FontSize.caption))
                                    .foregroundStyle(AppDesign.textSecondary)
                            }
                            Text(item.orderNumber)
                                .font(.system(size: AppMetrics.FontSize.footnote))
                                .foregroundStyle(AppDesign.textSecondary)
                            Text(item.userPhone)
                                .font(.system(size: AppMetrics.FontSize.footnote))
                                .foregroundStyle(AppDesign.textSecondary)
                        }
                        .padding(.vertical, AppMetrics.Spacing.xxSmall)
                    }
                } header: {
                    HStack {
                        Text(group.analyse.date)
                        Spacer()
                        Text("\(group.analyse.orderCount)笔 ¥\(group.analyse.orderAmountSum)")
                    }
                }
            }
        }
        .navigationTitle("收款记录")
        .navigationBarTitleDisplayMode(.inline)
        .refreshable {
            await viewModel.load(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
        }
        .task(id: accountContext.currentScenic?.id) {
            await globalLoading.withOptionalLoading(viewModel.groups.isEmpty, message: "加载中...") {
                await viewModel.load(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
            }
        }
        .onChange(of: viewModel.errorMessage) { _, message in
            if let message {
                toastCenter.show(message)
            }
        }
    }
}

/// 收款语音播报服务，使用系统 TTS 播报到账提示。
@MainActor
@Observable
final class PaymentVoiceSpeaker {
    @ObservationIgnored private let synthesizer = AVSpeechSynthesizer()

    /// 播报指定中文文案。
    func speak(_ text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "zh-CN")
        utterance.rate = 0.5
        synthesizer.speak(utterance)
    }
}
