//
//  PunchPointViews.swift
//  suixinkan
//
//  Created by Codex on 2026/6/24.
//

import PhotosUI
import SwiftUI
import UIKit

/// 打卡点列表页面，展示当前景区下的打卡点并提供新增入口。
struct PunchPointListView: View {
    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.accountContextAPI) private var accountContextAPI
    @Environment(\.punchPointAPI) private var punchPointAPI
    @EnvironmentObject private var router: RouterPath
    @EnvironmentObject private var scenicSpotContext: ScenicSpotContext
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.globalLoading) private var globalLoading

    @StateObject private var viewModel = PunchPointListViewModel()

    var body: some View {
        ScrollView {
            LazyVStack(spacing: AppMetrics.Spacing.medium) {
                filterSection
                contentSection
            }
            .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
            .padding(.vertical, AppMetrics.Spacing.medium)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("打卡点管理")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button {
                    router.navigate(to: .home(.punchPointEditor(id: nil)))
                } label: {
                    Image(systemName: "plus")
                }
                .accessibilityLabel("新增打卡点")
            }
        }
        .refreshable { await reload(showLoading: false) }
        .task {
            guard viewModel.items.isEmpty else { return }
            await reload(showLoading: true)
        }
    }

    /// 筛选区域。
    private var filterSection: some View {
        Picker("打卡点状态", selection: $viewModel.selectedFilter) {
            ForEach(PunchPointFilter.allCases) { filter in
                Text(filter.title).tag(filter)
            }
        }
        .pickerStyle(.segmented)
        .onChange(of: viewModel.selectedFilter) { newValue in
            Task {
                await globalLoading.withOptionalLoading(currentScenicId != nil) {
                    await viewModel.selectFilter(newValue, scenicId: currentScenicId, api: punchPointAPI)
                }
            }
        }
    }

    /// 内容区域。
    @ViewBuilder
    private var contentSection: some View {
        if currentScenicId == nil {
            PunchPointEmptyState(title: "缺少景区上下文", message: "请先在首页选择景区后再管理打卡点。")
        } else if viewModel.items.isEmpty {
            PunchPointEmptyState(title: "暂无打卡点", message: viewModel.errorMessage ?? "当前筛选条件下没有打卡点。")
        } else {
            ForEach(viewModel.items) { item in
                Button {
                    router.navigate(to: .home(.punchPointDetail(id: item.id, summary: item)))
                } label: {
                    PunchPointCardView(item: item)
                }
                .buttonStyle(.plain)
                .onAppear {
                    guard item.id == viewModel.items.last?.id else { return }
                    Task { await loadMore() }
                }
            }
            if viewModel.isLoadingMore {
                ProgressView()
                    .padding(.vertical, AppMetrics.Spacing.medium)
            }
        }
    }

    private var currentScenicId: Int? {
        accountContext.currentScenic?.id
    }

    /// 重新加载列表。
    private func reload(showLoading: Bool) async {
        await globalLoading.withOptionalLoading(showLoading && currentScenicId != nil) {
            await viewModel.reload(scenicId: currentScenicId, api: punchPointAPI)
        }
    }

    /// 加载下一页。
    private func loadMore() async {
        await viewModel.loadMore(scenicId: currentScenicId, api: punchPointAPI)
    }
}

/// 打卡点详情页面，展示点位信息、图片和管理操作。
struct PunchPointDetailView: View {
    let punchPointId: Int
    let summary: PunchPointItem?

    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.accountContextAPI) private var accountContextAPI
    @Environment(\.punchPointAPI) private var punchPointAPI
    @EnvironmentObject private var router: RouterPath
    @EnvironmentObject private var scenicSpotContext: ScenicSpotContext
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.globalLoading) private var globalLoading

    @StateObject private var viewModel = PunchPointListViewModel()
    @State private var showDeleteConfirm = false

    var item: PunchPointItem? {
        viewModel.selectedDetail ?? summary
    }

    var body: some View {
        ScrollView {
            VStack(spacing: AppMetrics.Spacing.medium) {
                if let item {
                    detailHeader(item)
                    imageSection(item)
                    infoSection(item)
                } else {
                    PunchPointEmptyState(title: "暂无详情", message: viewModel.errorMessage ?? "请稍后重试。")
                }
            }
            .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
            .padding(.vertical, AppMetrics.Spacing.medium)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("打卡点详情")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItemGroup(placement: .topBarTrailing) {
                if let item {
                    Button {
                        router.navigate(to: .home(.punchPointQR(id: item.id, title: item.name, qrURL: item.mpQrcode)))
                    } label: {
                        Image(systemName: "qrcode")
                    }
                    Button {
                        router.navigate(to: .home(.punchPointEditor(id: item.id)))
                    } label: {
                        Image(systemName: "square.and.pencil")
                    }
                    Button(role: .destructive) {
                        showDeleteConfirm = true
                    } label: {
                        Image(systemName: "trash")
                    }
                }
            }
        }
        .confirmationDialog("确认删除该打卡点？", isPresented: $showDeleteConfirm, titleVisibility: .visible) {
            Button("删除", role: .destructive) {
                Task { await deleteCurrentItem() }
            }
        }
        .task {
            await globalLoading.withOptionalLoading(summary == nil) {
                await viewModel.loadDetail(id: punchPointId, api: punchPointAPI)
            }
        }
    }

    /// 详情头部。
    private func detailHeader(_ item: PunchPointItem) -> some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
            HStack {
                Text(item.name)
                    .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
                    .foregroundStyle(AppDesign.textPrimary)
                Spacer()
                Text(item.statusLabel.isEmpty ? "状态 \(item.status)" : item.statusLabel)
                    .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                    .foregroundStyle(AppDesign.primary)
                    .padding(.horizontal, AppMetrics.Spacing.small)
                    .padding(.vertical, AppMetrics.Spacing.xSmall)
                    .background(AppDesign.primarySoft, in: Capsule())
            }
            Text(item.description.isEmpty ? "暂无描述" : item.description)
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.textSecondary)
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 图片区域。
    private func imageSection(_ item: PunchPointItem) -> some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
            Text("打卡点图片")
                .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
            if item.guideImages.isEmpty {
                Text("暂无图片")
                    .font(.system(size: AppMetrics.FontSize.subheadline))
                    .foregroundStyle(AppDesign.textSecondary)
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: AppMetrics.Spacing.small) {
                        ForEach(item.guideImages, id: \.self) { url in
                            RemoteImage(urlString: url) {
                                Image(systemName: "photo")
                                    .foregroundStyle(AppDesign.placeholder)
                                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                                    .background(Color(hex: 0xEEF2F6))
                            }
                            .frame(width: 128, height: 92)
                            .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
                        }
                    }
                }
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 基础信息区域。
    private func infoSection(_ item: PunchPointItem) -> some View {
        VStack(spacing: AppMetrics.Spacing.small) {
            PunchPointInfoRow(title: "地址", value: item.region?.address ?? "暂无")
            PunchPointInfoRow(title: "坐标", value: coordinateText(for: item))
            PunchPointInfoRow(title: "创建时间", value: nonEmpty(item.createdAt) ?? "暂无")
            PunchPointInfoRow(title: "创建人", value: nonEmpty(item.creator) ?? "暂无")
            if !item.auditRemark.isEmpty {
                PunchPointInfoRow(title: "审核备注", value: item.auditRemark)
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 坐标展示文案。
    private func coordinateText(for item: PunchPointItem) -> String {
        guard let region = item.region else { return "暂无" }
        return "\(region.lat), \(region.lot)"
    }

    /// 删除当前打卡点。
    private func deleteCurrentItem() async {
        guard let item else { return }
        let success = await globalLoading.withLoading {
            await viewModel.delete(item, scenicId: accountContext.currentScenic?.id, api: punchPointAPI)
        }
        if success {
            toastCenter.show("删除成功")
            await scenicSpotContext.reload(scenicId: accountContext.currentScenic?.id, api: accountContextAPI)
            router.path.removeLast()
        } else {
            toastCenter.show(viewModel.errorMessage ?? "删除失败")
        }
    }
}

/// 打卡点编辑页面，用于新增或修改点位。
struct PunchPointEditorView: View {
    let punchPointId: Int?

    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.accountContextAPI) private var accountContextAPI
    @Environment(\.punchPointAPI) private var punchPointAPI
    @Environment(\.ossUploadService) private var uploadService
    @EnvironmentObject private var scenicSpotContext: ScenicSpotContext
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.dismiss) private var dismiss
    @Environment(\.globalLoading) private var globalLoading

    @StateObject private var detailLoader = PunchPointListViewModel()
    @StateObject private var viewModel = PunchPointEditorViewModel()
    @State private var locationProvider = ForegroundLocationProvider()
    @State private var selectedItems: [PhotosPickerItem] = []

    var body: some View {
        ScrollView {
            VStack(spacing: AppMetrics.Spacing.medium) {
                formSection
                locationSection
                imageSection
                submitButton
            }
            .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
            .padding(.vertical, AppMetrics.Spacing.medium)
        }
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle(punchPointId == nil ? "新增打卡点" : "编辑打卡点")
        .navigationBarTitleDisplayMode(.inline)
        .task {
            guard let punchPointId else { return }
            await globalLoading.withOptionalLoading(detailLoader.selectedDetail == nil) {
                await detailLoader.loadDetail(id: punchPointId, api: punchPointAPI)
                if let detail = detailLoader.selectedDetail {
                    viewModel.apply(detail)
                }
            }
        }
        .onChange(of: selectedItems) { items in
            Task { await loadPickedImages(items) }
        }
    }

    /// 表单区域。
    private var formSection: some View {
        VStack(spacing: AppMetrics.Spacing.small) {
            TextField("打卡点名称", text: $viewModel.name)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
            TextField("打卡点描述", text: $viewModel.description, axis: .vertical)
                .lineLimit(3, reservesSpace: true)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: 96)
            TextField("打卡点展示名称", text: $viewModel.scenicSpotText)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 坐标和地址区域。
    private var locationSection: some View {
        VStack(spacing: AppMetrics.Spacing.small) {
            TextField("地址", text: $viewModel.address)
                .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
            HStack(spacing: AppMetrics.Spacing.small) {
                TextField("纬度", text: $viewModel.latitudeText)
                    .keyboardType(.decimalPad)
                    .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
                TextField("经度", text: $viewModel.longitudeText)
                    .keyboardType(.decimalPad)
                    .appInputFieldStyle(cornerRadius: AppMetrics.CornerRadius.input, minHeight: AppMetrics.ControlSize.inputHeight)
            }
            Button {
                Task { await locateForPunchPoint() }
            } label: {
                Label("使用当前位置", systemImage: "location")
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 图片选择区域。
    private var imageSection: some View {
        VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
            HStack {
                Text("打卡点图片")
                    .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
                Spacer()
                PhotosPicker(selection: $selectedItems, maxSelectionCount: 9, matching: .images) {
                    Label("选择图片", systemImage: "photo.on.rectangle")
                }
            }

            LazyVGrid(columns: [GridItem(.adaptive(minimum: 92), spacing: AppMetrics.Spacing.small)], spacing: AppMetrics.Spacing.small) {
                ForEach(viewModel.remoteImages, id: \.self) { url in
                    ZStack(alignment: .topTrailing) {
                        RemoteImage(urlString: url) {
                            Image(systemName: "photo")
                                .foregroundStyle(AppDesign.placeholder)
                                .frame(maxWidth: .infinity, maxHeight: .infinity)
                                .background(Color(hex: 0xEEF2F6))
                        }
                        .frame(height: 92)
                        .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
                        imageRemoveButton { viewModel.removeRemoteImage(url) }
                    }
                }
                ForEach(viewModel.localImages) { image in
                    ZStack(alignment: .topTrailing) {
                        if let uiImage = UIImage(data: image.data) {
                            Image(uiImage: uiImage)
                                .resizable()
                                .scaledToFill()
                                .frame(height: 92)
                                .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
                        }
                        if image.progress > 0 && image.progress < 100 {
                            Text("\(image.progress)%")
                                .font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
                                .foregroundStyle(.white)
                                .padding(4)
                                .background(.black.opacity(0.55), in: Capsule())
                                .padding(4)
                        }
                        imageRemoveButton { viewModel.removeLocalImage(id: image.id) }
                    }
                }
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }

    /// 提交按钮。
    private var submitButton: some View {
        Button {
            Task { await submit() }
        } label: {
            Text(viewModel.isSubmitting ? "提交中..." : "保存")
                .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                .frame(maxWidth: .infinity)
                .frame(height: AppMetrics.ControlSize.primaryButtonHeight)
        }
        .buttonStyle(.borderedProminent)
        .disabled(viewModel.isSubmitting)
    }

    /// 图片删除按钮。
    private func imageRemoveButton(action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Image(systemName: "xmark.circle.fill")
                .foregroundStyle(.white, AppDesign.textSecondary)
                .padding(4)
        }
        .buttonStyle(.plain)
    }

    /// 使用当前位置回填点位。
    private func locateForPunchPoint() async {
        do {
            let result = try await locationProvider.requestCurrentLocation()
            viewModel.applyLocation(latitude: result.latitude, longitude: result.longitude, address: result.address)
        } catch {
            toastCenter.show("定位失败：\(error.localizedDescription)")
        }
    }

    /// 读取 PhotosPicker 图片。
    private func loadPickedImages(_ items: [PhotosPickerItem]) async {
        var images: [PunchPointLocalImage] = []
        for item in items {
            guard let data = try? await item.loadTransferable(type: Data.self) else { continue }
            images.append(PunchPointLocalImage(data: data, fileName: "punch_\(UUID().uuidString).jpg"))
        }
        viewModel.addLocalImages(images)
        selectedItems = []
    }

    /// 提交表单。
    private func submit() async {
        let success = await globalLoading.withLoading {
            await viewModel.submit(scenicId: accountContext.currentScenic?.id, api: punchPointAPI, uploadService: uploadService)
        }
        if success {
            toastCenter.show("保存成功")
            await scenicSpotContext.reload(scenicId: accountContext.currentScenic?.id, api: accountContextAPI)
            dismiss()
        } else {
            toastCenter.show(viewModel.errorMessage ?? "保存失败")
        }
    }
}

/// 打卡点二维码页面。
struct PunchPointQRView: View {
    let title: String
    let qrURL: String

    var body: some View {
        VStack(spacing: AppMetrics.Spacing.large) {
            Text(title)
                .font(.system(size: AppMetrics.FontSize.title2, weight: .semibold))
                .foregroundStyle(AppDesign.textPrimary)
            RemoteImage(urlString: qrURL, contentMode: .fit) {
                Image(systemName: "qrcode")
                    .font(.system(size: 96, weight: .semibold))
                    .foregroundStyle(AppDesign.placeholder)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color(hex: 0xEEF2F6))
            }
            .frame(width: 240, height: 240)
            .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
            Text(qrURL.isEmpty ? "暂无二维码" : qrURL)
                .font(.system(size: AppMetrics.FontSize.caption))
                .foregroundStyle(AppDesign.textSecondary)
                .multilineTextAlignment(.center)
                .padding(.horizontal, AppMetrics.Spacing.large)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(hex: 0xF5F7FA))
        .navigationTitle("打卡点二维码")
        .navigationBarTitleDisplayMode(.inline)
    }
}

/// 打卡点卡片组件。
private struct PunchPointCardView: View {
    let item: PunchPointItem

    var body: some View {
        HStack(spacing: AppMetrics.Spacing.medium) {
            RemoteImage(urlString: item.guideImages.first) {
                Image(systemName: "mappin.and.ellipse")
                    .foregroundStyle(AppDesign.primary)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(AppDesign.primarySoft)
            }
            .frame(width: 82, height: 72)
            .clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))

            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xSmall) {
                HStack {
                    Text(item.name)
                        .font(.system(size: AppMetrics.FontSize.body, weight: .semibold))
                        .foregroundStyle(AppDesign.textPrimary)
                        .lineLimit(1)
                    Spacer()
                    Text(item.statusLabel.isEmpty ? "状态 \(item.status)" : item.statusLabel)
                        .font(.system(size: AppMetrics.FontSize.caption))
                        .foregroundStyle(AppDesign.primary)
                }
                Text(item.region?.address ?? "暂无地址")
                    .font(.system(size: AppMetrics.FontSize.subheadline))
                    .foregroundStyle(AppDesign.textSecondary)
                    .lineLimit(2)
                Text(nonEmpty(item.createdAt) ?? "暂无创建时间")
                    .font(.system(size: AppMetrics.FontSize.caption))
                    .foregroundStyle(AppDesign.placeholder)
            }
        }
        .padding(AppMetrics.Spacing.medium)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }
}

/// 返回去除空白后的非空字符串。
private func nonEmpty(_ text: String) -> String? {
    let value = text.trimmingCharacters(in: .whitespacesAndNewlines)
    return value.isEmpty ? nil : value
}

/// 打卡点信息行组件。
private struct PunchPointInfoRow: View {
    let title: String
    let value: String

    var body: some View {
        HStack(alignment: .top) {
            Text(title)
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.textSecondary)
                .frame(width: 76, alignment: .leading)
            Text(value)
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.textPrimary)
                .multilineTextAlignment(.leading)
            Spacer(minLength: 0)
        }
    }
}

/// 打卡点空状态组件。
private struct PunchPointEmptyState: View {
    let title: String
    let message: String

    var body: some View {
        VStack(spacing: AppMetrics.Spacing.small) {
            Image(systemName: "mappin.slash")
                .font(.system(size: 34, weight: .semibold))
                .foregroundStyle(AppDesign.placeholder)
            Text(title)
                .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
                .foregroundStyle(AppDesign.textPrimary)
            Text(message)
                .font(.system(size: AppMetrics.FontSize.subheadline))
                .foregroundStyle(AppDesign.textSecondary)
                .multilineTextAlignment(.center)
        }
        .frame(maxWidth: .infinity)
        .padding(AppMetrics.Spacing.xLarge)
        .background(.white, in: RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
    }
}
