import SwiftUI
import SwiftData

struct DownloadBrowserView: View {
    @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss

    @State private var baseURLText: String = ""
    @State private var courses: [RemoteCourseSummary] = []
    @State private var selected: Set<String> = []
    @State private var busy = false
    @State private var statusMessage: String?
    @State private var errorMessage: String?
    @State private var results: [String] = []
    @State private var showScanner = false
    /// `0…1` while a pack file is transferring; nil when idle / installing.
    @State private var downloadProgress: Double?

    private var store: CourseStore { CourseStore(modelContext: modelContext) }

    var body: some View {
        Form {
            Section {
                HStack(spacing: 10) {
                    TextField("电脑地址，如 http://192.168.50.157:8787", text: $baseURLText)
                        .textInputAutocapitalization(.never)
                        .autocorrectionDisabled()
                        .keyboardType(.URL)
                    Button {
                        showScanner = true
                    } label: {
                        Image(systemName: "qrcode")
                            .font(.title3)
                            .frame(width: 28, height: 28)
                    }
                    .buttonStyle(.borderless)
                    .accessibilityLabel("扫描二维码")
                    .disabled(busy)
                }
                Button {
                    Task { await loadCatalog() }
                } label: {
                    if busy {
                        ProgressView()
                    } else {
                        Text("连接并获取课程列表")
                    }
                }
                .disabled(busy || baseURLText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
            } footer: {
                Text("请先在电脑 StudyDeck 打开「分享到 iPad」。可扫码或手动填入地址。仅信任局域网使用。")
            }

            if !courses.isEmpty {
                Section("可下载课程") {
                    ForEach(courses) { course in
                        Toggle(isOn: Binding(
                            get: { selected.contains(course.id) },
                            set: { on in
                                if on { selected.insert(course.id) } else { selected.remove(course.id) }
                            }
                        )) {
                            VStack(alignment: .leading, spacing: 4) {
                                Text(course.title).font(.headline)
                                Text("\(course.mode == "playlist" ? "专辑" : "课程") · 更新 \(course.updatedAt) · \(course.itemCount ?? 0) 项")
                                    .font(.caption)
                                    .foregroundStyle(.secondary)
                            }
                        }
                    }
                    Button {
                        Task { await downloadSelected() }
                    } label: {
                        if busy {
                            HStack(spacing: 10) {
                                if let downloadProgress {
                                    ProgressView(value: downloadProgress)
                                        .frame(maxWidth: 120)
                                    Text(Self.formatPercent(downloadProgress))
                                        .font(.subheadline.monospacedDigit())
                                        .foregroundStyle(.secondary)
                                } else {
                                    ProgressView()
                                }
                            }
                        } else {
                            Text("下载所选 (\(selected.count))")
                        }
                    }
                    .disabled(busy || selected.isEmpty)
                }
            }

            if let statusMessage {
                Section("状态") {
                    Text(statusMessage)
                    if let downloadProgress {
                        VStack(alignment: .leading, spacing: 8) {
                            ProgressView(value: downloadProgress)
                            Text(Self.formatPercent(downloadProgress))
                                .font(.caption.monospacedDigit())
                                .foregroundStyle(.secondary)
                        }
                        .padding(.top, 4)
                    }
                }
            }
            if !results.isEmpty {
                Section("结果") {
                    ForEach(results, id: \.self) { Text($0) }
                }
            }
        }
        .navigationTitle("添加课程")
        .navigationBarTitleDisplayMode(.inline)
        .onAppear {
            if baseURLText.isEmpty {
                baseURLText = store.settings().lastPublishBaseURL ?? ""
            }
        }
        .sheet(isPresented: $showScanner) {
            QRScannerView { scanned in
                applyScannedURL(scanned)
            }
        }
        .alert("提示", isPresented: Binding(
            get: { errorMessage != nil },
            set: { if !$0 { errorMessage = nil } }
        )) {
            Button("好", role: .cancel) {}
        } message: {
            Text(errorMessage ?? "")
        }
    }

    private func applyScannedURL(_ raw: String) {
        guard let url = PublishClient.normalizeBaseURL(raw) else {
            errorMessage = "二维码内容不是有效地址"
            return
        }
        baseURLText = url.absoluteString
        Task { await loadCatalog() }
    }

    @MainActor
    private func loadCatalog() async {
        busy = true
        defer { busy = false }
        results = []
        statusMessage = nil
        guard let base = PublishClient.normalizeBaseURL(baseURLText) else {
            errorMessage = "地址无效"
            return
        }
        do {
            courses = try await PublishClient.fetchCourses(baseURL: base)
            store.settings().lastPublishBaseURL = base.absoluteString
            try? modelContext.save()
            selected = Set(courses.map(\.id))
            statusMessage = "已找到 \(courses.count) 个课程"
            if courses.isEmpty {
                statusMessage = "电脑上还没有可分享的专辑或课程"
            }
        } catch {
            courses = []
            errorMessage = error.localizedDescription
        }
    }

    @MainActor
    private func downloadSelected() async {
        busy = true
        defer {
            busy = false
            downloadProgress = nil
        }
        guard let base = PublishClient.normalizeBaseURL(baseURLText) else {
            errorMessage = "地址无效"
            return
        }
        results = []
        for id in selected {
            let course = courses.first(where: { $0.id == id })
            let title = course?.title ?? id
            let remoteUpdated = course?.updatedAt ?? ""
            if let existing = store.course(id: id),
               !remoteUpdated.isEmpty,
               remoteUpdated <= existing.updatedAtRemote {
                results.append("跳过 \(title)（本地已是最新）")
                continue
            }
            downloadProgress = 0
            statusMessage = "正在下载 \(title)… 0%"
            do {
                let zip = try await PublishClient.downloadPack(
                    baseURL: base,
                    courseId: id,
                    expectedBytes: course?.byteSize
                ) { fraction in
                    let pct = Self.formatPercent(fraction)
                    Task { @MainActor in
                        downloadProgress = fraction
                        statusMessage = "正在下载 \(title)… \(pct)"
                    }
                }
                defer { try? FileManager.default.removeItem(at: zip) }
                downloadProgress = nil
                statusMessage = "正在安装 \(title)…"
                let unpacked = try CourseLibrary.unzipPack(zipURL: zip)
                defer { try? FileManager.default.removeItem(at: unpacked) }
                let manifest = try CourseLibrary.installUnpackedDirectory(at: unpacked)
                _ = try store.registerInstalled(manifest: manifest)
                results.append("成功 \(manifest.title)")
            } catch {
                downloadProgress = nil
                results.append("失败 \(title): \(error.localizedDescription)")
            }
        }
        statusMessage = "下载完成"
        store.settings().lastPublishBaseURL = base.absoluteString
        try? modelContext.save()
    }

    private static func formatPercent(_ value: Double) -> String {
        "\(Int((value * 100).rounded()))%"
    }
}
