//
//  WiredCameraTransferView.swift
//  suixinkan
//
//  Created by Codex on 2026/6/29.
//

import SwiftUI

/// 有线传图页，连接相机并上传照片到旅拍相册。
struct WiredCameraTransferView: View {
    let context: WiredTransferContext

    @EnvironmentObject private var accountContext: AccountContext
    @Environment(\.travelAlbumAPI) private var travelAlbumAPI
    @Environment(\.ossUploadService) private var ossUploadService
    @EnvironmentObject private var toastCenter: ToastCenter
    @Environment(\.dismiss) private var dismiss
    @Environment(\.scenePhase) private var scenePhase

    @StateObject private var viewModel: WiredCameraTransferViewModel
    @State private var previewSources: [String]?
    @State private var previewStartIndex = 0

    init(context: WiredTransferContext) {
        self.context = context
        _viewModel = StateObject(
            wrappedValue: WiredCameraTransferViewModel(
                context: context,
                cameraService: CameraServiceFactory.makeAutoDetect()
            )
        )
    }

    private let tabTitles = ["全部", "已上传", "失败"]
    private var scenicID: Int { accountContext.currentScenic?.id ?? 0 }
    private var scenicSpotLabel: String? {
        accountContext.currentScenic?.name
    }

    var body: some View {
        VStack(spacing: 0) {
            WiredTransferHeaderView(
                albumTitle: context.albumName,
                headerPhone: context.phone,
                onBack: { dismiss() }
            )

            WiredTransferControlCard(
                scenicSpotLabel: scenicSpotLabel,
                deviceStorageInfo: viewModel.deviceStorageInfo,
                isCameraConnected: viewModel.isCameraConnected,
                isRefreshingCameraFiles: viewModel.isRefreshingCameraFiles,
                isSearchingCamera: viewModel.isSearchingCamera,
                cameraDeviceName: viewModel.cameraDeviceName,
                transferModeOption: viewModel.transferModeOption,
                tabTitles: tabTitles,
                tabCounts: viewModel.tabCounts,
                selectedTabIndex: viewModel.selectedTabIndex,
                onDeviceUsageClick: viewModel.onDeviceUsageClick,
                onRefreshCameraFiles: {
                    Task { await viewModel.refreshCameraFiles() }
                },
                onHelpClick: viewModel.openHelpDoc,
                onTransferModeSelected: { option in
                    viewModel.selectTransferMode(
                        option,
                        api: travelAlbumAPI,
                        ossService: ossUploadService,
                        scenicID: scenicID
                    )
                },
                onTabSelected: viewModel.selectTab
            )

            if viewModel.selectUploadMode, !visiblePhotos.isEmpty {
                selectAllBar
            }

            contentSection

            WiredTransferBottomBar(
                selectUploadMode: viewModel.selectUploadMode,
                selectedCount: viewModel.selectedPhotoIDs.count,
                onBatchUploadClick: {
                    Task {
                        await viewModel.onBatchUploadButtonClick(
                            api: travelAlbumAPI,
                            ossService: ossUploadService,
                            scenicID: scenicID
                        )
                    }
                },
                onSpecifyUploadClick: viewModel.onSpecifyUploadButtonClick
            )
        }
        .background(WiredTransferDesign.pageBackground.ignoresSafeArea())
        .toolbar(.hidden, for: .navigationBar)
        .task {
            await viewModel.start(
                api: travelAlbumAPI,
                ossService: ossUploadService,
                scenicID: scenicID,
                accountContext: accountContext
            )
        }
        .onDisappear {
            viewModel.detachFromUI()
        }
        .onChange(of: scenePhase) { phase in
            guard phase == .active, !viewModel.isCameraConnected else { return }
            Task { await viewModel.restartCameraSearch() }
        }
        .onChange(of: viewModel.errorMessage) { message in
            guard let message, !message.isEmpty else { return }
            toastCenter.show(message)
            viewModel.clearErrorMessage()
        }
        .onChange(of: viewModel.connectionState) { state in
            switch state {
            case .connected(let name):
                toastCenter.show("已连接 \(name)")
            case .error(let message):
                toastCenter.show(message)
            default:
                break
            }
        }
        .alert("手机内存不足", isPresented: $viewModel.showDeviceStorageAlert) {
            Button("我知道了", role: .cancel) {}
        } message: {
            Text("请及时清理内存")
        }
        .alert("相机已断开", isPresented: $viewModel.showCameraDisconnectedAlert) {
            Button("我知道了", role: .cancel) {}
        } message: {
            Text("相机已断开，请检查 USB 连接。")
        }
        .sheet(isPresented: $viewModel.showSpecifyUploadSheet) {
            SpecifyUploadBottomSheet(isPresented: $viewModel.showSpecifyUploadSheet) { option in
                Task {
                    await viewModel.onSpecifyUploadOptionSelected(
                        option,
                        api: travelAlbumAPI,
                        ossService: ossUploadService,
                        scenicID: scenicID
                    )
                }
            }
            .presentationDetents([.height(360)])
            .presentationDragIndicator(.hidden)
        }
        .sheet(isPresented: $viewModel.showHelpDoc) {
            NavigationStack {
                WiredTransferHelpDocView(url: WiredCameraTransferViewModel.helpDocURL)
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button("关闭") { viewModel.showHelpDoc = false }
                        }
                    }
            }
        }
        .sheet(item: previewBinding) { item in
            WiredTransferPhotoPreviewSheet(
                imageSources: item.sources,
                startIndex: item.startIndex,
                onDismiss: { previewSources = nil }
            )
        }
    }

    private var visiblePhotos: [WiredTransferPhotoItem] {
        viewModel.visiblePhotos
    }

    private var sidebarGroups: [WiredTransferDateGroup] {
        viewModel.sidebarGroups
    }

    private var photoSections: [WiredTransferPhotoSection] {
        viewModel.photoSections
    }

    private var selectAllBar: some View {
        let pendingIDs = visiblePhotos.selectablePendingPhotoIDs
        let allSelected = !pendingIDs.isEmpty && pendingIDs.isSubset(of: viewModel.selectedPhotoIDs)
        return WiredTransferSelectAllBar(
            selectedCount: viewModel.selectedPhotoIDs.count,
            selectableCount: pendingIDs.count,
            allSelected: allSelected,
            onToggleSelectAll: viewModel.toggleSelectAllPendingInVisible
        )
    }

    @ViewBuilder
    private var contentSection: some View {
        if visiblePhotos.isEmpty {
            WiredTransferEmptyState()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        } else {
            WiredTransferPhotoListPanel(
                sidebarExpanded: viewModel.sidebarExpanded,
                sidebarGroups: sidebarGroups,
                photoSections: photoSections,
                selectedTimeSlotID: viewModel.selectedTimeSlotID,
                selectUploadMode: viewModel.selectUploadMode,
                selectedPhotoIDs: viewModel.selectedPhotoIDs,
                onToggleSidebar: viewModel.toggleSidebar,
                onTimeSlotSelected: viewModel.selectTimeSlot,
                onPhotoClick: openPhotoPreview,
                onRetry: { id in
                    Task {
                        await viewModel.retryPhoto(
                            id: id,
                            api: travelAlbumAPI,
                            ossService: ossUploadService,
                            scenicID: scenicID
                        )
                    }
                },
                onDelete: viewModel.deletePhoto,
                onTogglePhotoSelection: viewModel.togglePhotoSelection
            )
        }
    }

    private var previewBinding: Binding<PreviewPayload?> {
        Binding(
            get: {
                guard let previewSources else { return nil }
                return PreviewPayload(sources: previewSources, startIndex: previewStartIndex)
            },
            set: { newValue in
                if newValue == nil { previewSources = nil }
            }
        )
    }

    private func openPhotoPreview(photoID: String) {
        let entries = visiblePhotos.compactMap { photo -> String? in
            let url = viewModel.previewURL(for: photo.id)
            return url.isEmpty ? nil : url
        }
        guard let startIndex = visiblePhotos.firstIndex(where: { $0.id == photoID }),
              !viewModel.previewURL(for: photoID).isEmpty else {
            toastCenter.show("暂无法预览该照片")
            return
        }
        let mappedIndex = visiblePhotos.prefix(startIndex + 1).filter {
            !viewModel.previewURL(for: $0.id).isEmpty
        }.count - 1
        previewStartIndex = max(mappedIndex, 0)
        previewSources = entries
    }
}

/// 预览 Sheet 载荷。
private struct PreviewPayload: Identifiable {
    let id = UUID()
    let sources: [String]
    let startIndex: Int
}
