import SwiftUI

struct ConfigureView: View {
    @Environment(WizardModel.self) private var model

    @State private var task: Task<Void, Never>?
    @State private var needsPushRetry = false
    @State private var lockProfileConfirmed = false
    @State private var configureReady = false
    @State private var appPushDone = false
    @State private var backendValidationDone = false
    @State private var didAutoFinish = false

    private let sideloadProfileID = "org.rebreak.protection.contentfilter.sideload"

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            header

            Text("Wir richten den Schutz jetzt automatisch ein: App-Setup per Push und anschließend Lock-Profil (non-removable) mit automatischer Prüfung.")
                .foregroundStyle(.secondary)

            TransferAnimationView(
                leftSymbol: "server.rack",
                rightSymbol: "iphone.gen3",
                title: "App-Setup",
                subtitle: appPushDone
                    ? "ReBreak-App Push/Management bestätigt."
                    : "ReBreak-Server pusht App-Setup auf das iPhone.",
                isActive: model.configureRunning && !appPushDone,
                isDone: appPushDone
            )

            TransferAnimationView(
                leftSymbol: "iphone.gen3",
                rightSymbol: "server.rack",
                title: "Lock + DNS Validierung",
                subtitle: backendValidationDone
                    ? "Lock-Profil aktiv und Backend-Check-In ist frisch."
                    : "Warte auf Lock-Profil und anschließende Backend-Bestätigung.",
                isActive: model.configureRunning && appPushDone && !backendValidationDone,
                isDone: backendValidationDone
            )

            stepList

            appPreStatus

            statusBox

            if model.showAdvancedLogs {
                logViewer
            }

            Button(model.showAdvancedLogs ? "Details ausblenden" : "Details anzeigen") {
                model.showAdvancedLogs.toggle()
            }
            .buttonStyle(.borderless)
            .foregroundStyle(.secondary)

            Spacer()

            navigationBar
        }
        .padding(40)
        .onAppear { startIfNeeded() }
        .onDisappear { task?.cancel() }
    }

    private var header: some View {
        HStack {
            Image(systemName: "shield.lefthalf.filled")
                .font(.system(size: 30))
                .foregroundStyle(.tint)
            Text("Schutz aktivieren")
                .font(.title).bold()
        }
    }

    private var stepList: some View {
        VStack(alignment: .leading, spacing: 6) {
            Label("Automatischer Pre-Check", systemImage: "magnifyingglass")
            Label("App-Setup + Managed-Status per Push", systemImage: "arrow.triangle.branch")
            Label("Lock-Profil (non-removable) anwenden", systemImage: "paperplane")
            Label("Automatische Verifikation", systemImage: "checkmark.seal")
        }
        .font(.callout)
        .foregroundStyle(.secondary)
    }

    /// Pre-Check Status der ReBreak-App auf dem iPhone.
    private var appPreStatus: some View {
        let installed = model.device?.installedAppBundleIDs.contains("org.rebreak.app") == true
        return HStack(spacing: 8) {
            Image(systemName: installed ? "checkmark.circle.fill" : "xmark.circle")
                .foregroundStyle(installed ? .green : .secondary)
            Text(installed
                ? "ReBreak-App ist bereits installiert. Wir setzen jetzt den Managed-Status."
                : "ReBreak-App noch nicht lokal sichtbar. Wir installieren sie jetzt automatisch per Push.")
                .font(.callout)
        }
        .padding(8)
        .background((installed ? Color.green : Color.blue).opacity(0.08))
        .cornerRadius(6)
    }

    @ViewBuilder
    private var statusBox: some View {
        if model.configureRunning {
            HStack(spacing: 8) {
                ProgressView().controlSize(.small)
                Text("Automatischer Schutz-Flow läuft …")
            }
            .padding(10)
            .background(Color.blue.opacity(0.08))
            .cornerRadius(6)
        } else if let err = model.configureError {
            HStack(alignment: .top, spacing: 8) {
                Image(systemName: "xmark.octagon").foregroundStyle(.red)
                Text(err).font(.callout)
            }
            .padding(10)
            .background(Color.red.opacity(0.08))
            .cornerRadius(6)
        } else if !model.configureLog.isEmpty {
            HStack {
                Image(systemName: "checkmark.circle.fill").foregroundStyle(.green)
                Text("Schutz vollständig validiert. Du kannst abschließen.")
            }
            .padding(10)
            .background(Color.green.opacity(0.08))
            .cornerRadius(6)
        }
    }

    private var logViewer: some View {
        ScrollViewReader { proxy in
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 2) {
                    ForEach(Array(model.configureLog.enumerated()), id: \.offset) { idx, line in
                        Text(line)
                            .font(.system(.caption, design: .monospaced))
                            .foregroundStyle(line.hasPrefix("✗") ? .red : .secondary)
                            .id(idx)
                    }
                }
                .padding(8)
                .frame(maxWidth: .infinity, alignment: .leading)
            }
            .background(Color.black.opacity(0.04))
            .cornerRadius(6)
            .frame(maxHeight: 200)
            .onChange(of: model.configureLog.count) { _, newCount in
                if newCount > 0 { proxy.scrollTo(newCount - 1, anchor: .bottom) }
            }
        }
    }

    private var navigationBar: some View {
        HStack {
            Button("Zurück") { model.goTo(.enroll) }
                .buttonStyle(.bordered)
                .disabled(model.configureRunning)
            Spacer()
            if configureReady {
                Text("Schutz bestätigt. Abschluss wird automatisch geöffnet …")
                    .font(.callout)
                    .foregroundStyle(.secondary)
                Button("Jetzt zu Fertig") { model.advance() }
                    .buttonStyle(.borderedProminent)
            } else {
                Text("Bitte kurz warten …")
                    .font(.callout)
                    .foregroundStyle(.secondary)
            }
        }
    }

    /// Pfad zur Sideload-Profile-Datei (nicht zur MDM-Push-Variante).
    /// User dropt die per AirDrop an's iPhone.
    private var sideloadProfilePath: String? {
        let home = FileManager.default.homeDirectoryForCurrentUser.path
        let candidates = [
            "\(home)/mono/rebreak-monorepo/ops/mdm/profiles/rebreak-content-filter-sideload.mobileconfig",
        ]
        return candidates.first(where: { FileManager.default.fileExists(atPath: $0) })
    }

    /// Öffnet macOS' NSSharingServicePicker mit AirDrop-Service vorausgewählt.
    /// User klickt das eigene iPhone an → File wird übertragen → iPhone fragt nach Install.
    private func sendViaAirDrop(path: String) {
        let url = URL(fileURLWithPath: path)
        guard let service = NSSharingService(named: .sendViaAirDrop) else {
            model.configureLog.append("⚠ AirDrop-Service nicht verfügbar — manuell per Finder teilen.")
            return
        }
        if service.canPerform(withItems: [url]) {
            service.perform(withItems: [url])
            model.configureLog.append("→ AirDrop-Sheet geöffnet — wähle dein iPhone aus.")
        } else {
            model.configureLog.append("⚠ AirDrop kann diese Datei nicht senden — manuell per Finder.")
            NSWorkspace.shared.activateFileViewerSelecting([url])
        }
    }

    private func startIfNeeded() {
        if model.configureLog.isEmpty && !model.configureRunning && model.configureError == nil {
            startConfigure()
        }
    }

    private func startConfigure() {
        guard let udid = model.device?.udid else {
            model.configureError = "Kein Device — bitte zurück zu Step 1."
            return
        }
        model.configureLog = []
        model.configureError = nil
        model.configureRunning = true
        needsPushRetry = false
        lockProfileConfirmed = false
        configureReady = false
        appPushDone = false
        backendValidationDone = false
        didAutoFinish = false
        task?.cancel()
        task = Task { @MainActor in
            do {
                // PRE-FLIGHT: real-check ob iPhone überhaupt enrolled ist + check-in macht
                model.configureLog.append("→ Pre-Flight: NanoMDM-Enrollment-Status …")
                let status = try await MDMStatus.query(udid: udid)
                if !status.isEnrolled {
                    throw NSError(domain: "Binder", code: 1, userInfo: [NSLocalizedDescriptionKey:
                        "iPhone ist NICHT in NanoMDM enrolled. Bitte Step 4 (Enroll) wiederholen."])
                }
                let pending = status.pendingCommandCount
                if let ack = status.lastAckAt {
                    let ageMin = Int(Date().timeIntervalSince(ack) / 60)
                    model.configureLog.append("✓ enrolled · letzter Ack vor \(ageMin) min · \(pending) pending")
                    if ageMin > 30 {
                        model.configureLog.append("⚠ Letzter Check-In ist alt (>30min). iPhone reagiert evtl. nicht.")
                        model.configureLog.append("⚠ Falls Commands nach 1min nicht ausgeführt: Step 4 (Enroll) wiederholen.")
                    }
                } else {
                    model.configureLog.append("⚠ Noch nie ge-acked. Enrollment vermutlich tot — Step 4 wiederholen.")
                }

                model.configureLog.append("→ Ping NanoMDM …")
                let version = try await MDMClient.ping()
                model.configureLog.append("✓ NanoMDM \(version.trimmingCharacters(in: .whitespacesAndNewlines))")

                // Marker für Post-Flight: alle Acks NACH diesem Zeitstempel
                // gehören zu unseren Commands. NanoMDM's enrollment_queue.active
                // bleibt nach Ack auf true — daher zählen wir command_results.
                let pushStartTime = Date()

                // Harte Variante fuer robuste Tests:
                // Wenn ReBreak-App schon da ist, zuerst per MDM-Command
                // (RemoveApplication) entfernen — KEIN cfgutil mehr, weil
                // cfgutil remove-app auf iOS 18+ den 804-Fehler wirft.
                let appAlreadyInstalled = await DeviceDetector.installedAppBundleIDs().contains("org.rebreak.app")
                if appAlreadyInstalled {
                    model.configureLog.append("→ Hard-Reinstall: vorhandene ReBreak-App wird via MDM entfernt …")
                    let removeResult = try await MDMClient.removeApp(udid: udid)
                    model.configureLog.append("✓ enqueued RemoveApplication: \(removeResult.commandUUID.prefix(8))")
                    let removed = await waitForAppInstalled(expectedInstalled: false)
                    if !removed {
                        throw NSError(domain: "Binder", code: 7, userInfo: [NSLocalizedDescriptionKey:
                            "MDM-RemoveApplication wurde gepusht aber iPhone hat App nicht entfernt. Bitte Step 4 (Enroll) wiederholen."])
                    }
                    model.configureLog.append("✓ Vorhandene ReBreak-App entfernt.")
                } else {
                    model.configureLog.append("→ ReBreak-App nicht vorhanden, starte frischen Install-Push.")
                }

                for attempt in 1...2 {
                    model.configureLog.append("→ [1/2] Push-Versuch \(attempt): InstallApplication …")
                    let r1 = try await MDMClient.installApp(udid: udid)
                    model.configureLog.append("✓ enqueued: \(r1.prefix(80))")

                    model.configureLog.append("→ [2/2] Push-Versuch \(attempt): Settings mdmSupervised=true …")
                    let r2 = try await MDMClient.setSupervisedMode(udid: udid)
                    model.configureLog.append("✓ enqueued: \(r2.prefix(80))")

                    model.configureLog.append("")
                    model.configureLog.append("Warte 30s und prüfe automatische Rückmeldung …")

                    // POST-FLIGHT: 30s warten + checken ob neue Acks NACH pushStartTime da sind
                    try? await Task.sleep(for: .seconds(30))
                    let after = try await MDMStatus.query(udid: udid)
                    let lastAckAfter = after.lastAckAt
                    let hasNewAck = (lastAckAfter ?? .distantPast) > pushStartTime
                    if !hasNewAck {
                        needsPushRetry = true
                        model.configureLog.append("⚠ Kein neuer Ack erkannt (Versuch \(attempt)).")
                        if attempt == 2 {
                            throw NSError(domain: "Binder", code: 2, userInfo: [NSLocalizedDescriptionKey:
                                "iPhone hat keine Pushes abgeholt. Bitte Enrollment-Verbindung prüfen."])
                        }
                        continue
                    }

                    model.configureLog.append("✓ iPhone hat ge-acked (\(lastAckAfter!.formatted(date: .omitted, time: .standard))).")

                    let appsAfter = await DeviceDetector.installedAppBundleIDs()
                    let isAppInstalled = appsAfter.contains("org.rebreak.app")
                    model.configureLog.append(isAppInstalled
                        ? "✓ ReBreak-App ist auf dem iPhone."
                        : "⚠ ReBreak-App noch nicht sichtbar (Versuch \(attempt)).")

                    model.configureLog.append("→ Verifiziere Managed-Status …")
                    let managed = try await MDMClient.checkAppIsManaged(udid: udid)
                    if isAppInstalled, managed == true {
                        model.device?.isManaged = true
                        needsPushRetry = false
                        appPushDone = true
                        break
                    }
                    needsPushRetry = true
                    if attempt == 2 {
                        throw NSError(domain: "Binder", code: 3, userInfo: [NSLocalizedDescriptionKey:
                            "App-Setup konnte nicht stabil verifiziert werden. Bitte Schritt erneut starten."])
                    }
                    model.configureLog.append("⚠ Automatischer Retry läuft …")
                }

                model.configureLog.append("")
                model.configureLog.append("→ [3/3] Installiere non-removable Lock-Profil …")
                guard let profilePath = sideloadProfilePath else {
                    throw NSError(domain: "Binder", code: 4, userInfo: [NSLocalizedDescriptionKey:
                        "Lock-Profil-Datei nicht gefunden."])
                }
                do {
                    try await DeviceDetector.installProfileSilently(path: profilePath)
                    model.configureLog.append("✓ Lock-Profil via USB installiert.")
                } catch {
                    // Falls cfgutil zwar Fehler liefert, das Profil aber dennoch
                    // bereits installiert wurde, kein AirDrop mehr öffnen.
                    let alreadyInstalled = await waitForLockProfileInstalled(maxChecks: 4, intervalSeconds: 2)
                    if alreadyInstalled {
                        model.configureLog.append("✓ Lock-Profil wurde trotz USB-Fehler erkannt. Kein AirDrop nötig.")
                    } else {
                        model.configureLog.append("⚠ USB-Install nicht möglich: \(error.localizedDescription)")
                        model.configureLog.append("→ Öffne AirDrop-Fallback für das Lock-Profil …")
                        sendViaAirDrop(path: profilePath)
                    }
                }

                let lockInstalled = await waitForLockProfileInstalled()
                if !lockInstalled {
                    throw NSError(domain: "Binder", code: 5, userInfo: [NSLocalizedDescriptionKey:
                        "Lock-Profil wurde noch nicht erkannt. Bitte iPhone-Dialog abschließen."])
                }
                lockProfileConfirmed = true
                model.device?.isFilterActive = true

                model.configureLog.append("→ Validiere frischen Backend-Check-In …")
                let backendOk = await waitForFreshBackendStatus(udid: udid)
                if !backendOk {
                    throw NSError(domain: "Binder", code: 6, userInfo: [NSLocalizedDescriptionKey:
                        "Backend-Bestätigung für aktiven Schutz fehlt noch. Bitte kurz warten und erneut versuchen."])
                }
                backendValidationDone = true

                configureReady = true
                model.configureLog.append("✓ Lock-Profil ist aktiv erkannt.")
                model.configureLog.append("✓ Backend-Status bestätigt aktiven Schutz.")
                model.configureRunning = false
                triggerAutomaticFinish()
            } catch {
                model.configureLog.append("✗ Fehler: \(error.localizedDescription)")
                model.configureError = error.localizedDescription
                model.configureRunning = false
            }
        }
    }

    private func waitForLockProfileInstalled(maxChecks: Int = 40, intervalSeconds: UInt64 = 3) async -> Bool {
        for _ in 0..<maxChecks {
            let ids = await DeviceDetector.installedProfileIDs()
            if ids.contains(sideloadProfileID) {
                return true
            }
            try? await Task.sleep(for: .seconds(intervalSeconds))
        }
        return false
    }

    private func waitForAppInstalled(expectedInstalled: Bool) async -> Bool {
        for _ in 0..<20 {
            let installed = await DeviceDetector.installedAppBundleIDs().contains("org.rebreak.app")
            if installed == expectedInstalled {
                return true
            }
            try? await Task.sleep(for: .seconds(2))
        }
        return false
    }

    private func waitForFreshBackendStatus(udid: String) async -> Bool {
        for _ in 0..<30 {
            if let status = try? await MDMStatus.query(udid: udid) {
                model.device?.enrollmentStatus = status
                if status.isEnrolled && status.isFresh {
                    return true
                }
            }
            try? await Task.sleep(for: .seconds(3))
        }
        return false
    }

    @MainActor
    private func triggerAutomaticFinish() {
        guard configureReady, !didAutoFinish else { return }
        didAutoFinish = true
        Task { @MainActor in
            try? await Task.sleep(for: .seconds(0.8))
            model.advance()
        }
    }
}
