import SwiftUI
import AppKit

struct TransferAnimationView: View {
    let leftSymbol: String
    let rightSymbol: String
    let title: String
    let subtitle: String
    let isActive: Bool
    let isDone: Bool

    @State private var animate = false

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text(title)
                .font(.callout.weight(.semibold))
            Text(subtitle)
                .font(.caption)
                .foregroundStyle(.secondary)

            HStack(spacing: 14) {
                iconNode(systemName: leftSymbol)

                ZStack(alignment: .leading) {
                    Capsule()
                        .fill(Color.gray.opacity(0.22))
                        .frame(height: 6)

                    if isDone {
                        Capsule()
                            .fill(Color.green)
                            .frame(height: 6)
                    } else if isActive {
                        Circle()
                            .fill(Color.accentColor)
                            .frame(width: 12, height: 12)
                            .offset(x: animate ? 150 : 0)
                            .animation(.easeInOut(duration: 1.2).repeatForever(autoreverses: false), value: animate)
                    }
                }
                .frame(width: 150)

                iconNode(systemName: rightSymbol)
            }
        }
        .padding(12)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color.accentColor.opacity(0.06))
        .cornerRadius(10)
        .onAppear {
            animate = isActive
        }
        .onChange(of: isActive) { _, active in
            animate = active
        }
    }

    private func iconNode(systemName: String) -> some View {
        ZStack {
            Circle()
                .fill(Color.accentColor.opacity(0.12))
                .frame(width: 34, height: 34)
            Image(systemName: systemName)
                .font(.system(size: 15, weight: .semibold))
                .foregroundStyle(.tint)
        }
    }
}

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

    @State private var downloadStatus: String?
    @State private var localPath: String?
    @State private var flowStatus: String?
    @State private var busy = false
    @State private var enrollmentReady = false
    @State private var pollTask: Task<Void, Never>?
    @State private var didAutoAdvance = false
    @State private var showUnlockModal = false
    @State private var enrollError: String?

    private let enrollmentProfileID = "org.rebreak.mdm.enrollment"

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

            Text("Wir installieren jetzt automatisch das Verbindungs-Profil für die Geräteverwaltung. Danach prüfen wir selbst, ob alles korrekt aktiv ist.")
                .foregroundStyle(.secondary)

            TransferAnimationView(
                leftSymbol: "iphone.gen3",
                rightSymbol: "server.rack",
                title: "Enrollment Live-Status",
                subtitle: enrollmentReady
                    ? "Profil aktiv und iPhone am ReBreak-Server bestätigt enrolled."
                    : "Warte auf Profil-Installation am iPhone und Backend-Enrollment.",
                isActive: busy && !enrollmentReady,
                isDone: enrollmentReady
            )

            instructions

            Spacer()

            navigationBar
        }
        .padding(40)
        .onAppear { startIfNeeded() }
        .onDisappear { pollTask?.cancel() }
        .alert("iPhone entsperren", isPresented: $showUnlockModal) {
            Button("Erneut versuchen") {
                if let path = localPath {
                    busy = true
                    runInstallFlow(path: path)
                }
            }
            Button("OK", role: .cancel) {}
        } message: {
            Text("Bitte iPhone entsperren und verbunden lassen. Danach erneut versuchen.")
        }
    }

    private var header: some View {
        HStack {
            Image(systemName: "doc.badge.gearshape")
                .font(.system(size: 30))
                .foregroundStyle(.tint)
            Text("Verbindung einrichten")
                .font(.title).bold()
        }
    }

    private var instructions: some View {
        VStack(alignment: .leading, spacing: 14) {
            stepRow(number: 1, text: "Profil wird automatisch geladen.")
            if let status = downloadStatus {
                HStack(spacing: 8) {
                    Image(systemName: localPath != nil ? "checkmark.circle.fill" : "arrow.down.circle")
                        .foregroundStyle(localPath != nil ? .green : .secondary)
                    Text(status).font(.caption).foregroundStyle(.secondary)
                }
                .padding(.leading, 36)
            }

            stepRow(number: 2, text: "Automatische Installation wird versucht.")
            if let status = flowStatus {
                HStack(spacing: 8) {
                    Image(systemName: enrollmentReady ? "checkmark.circle.fill" : (busy ? "hourglass" : "info.circle"))
                        .foregroundStyle(enrollmentReady ? .green : .secondary)
                    Text(status).font(.caption).foregroundStyle(.secondary)
                }
                .padding(.leading, 36)
            }

            stepRow(number: 3, text: "Wenn iOS den Profil-Dialog zeigt, bitte direkt am iPhone bestätigen.")
            stepRow(number: 4, text: "Wir warten automatisch auf Profil aktiv + Backend-Enroll und schalten dann Weiter frei.")
        }
    }

    private func stepRow(number: Int, text: String) -> some View {
        HStack(alignment: .top, spacing: 12) {
            ZStack {
                Circle().fill(Color.accentColor)
                Text("\(number)").foregroundStyle(.white).bold()
            }
            .frame(width: 24, height: 24)
            Text(text)
                .fixedSize(horizontal: false, vertical: true)
            Spacer()
        }
    }

    private var navigationBar: some View {
        HStack {
            Button("Zurück") { model.goTo(.supervise) }
                .buttonStyle(.bordered)
                .disabled(busy)
            Spacer()
            if let err = enrollError {
                HStack(spacing: 8) {
                    Text(err)
                        .font(.callout)
                        .foregroundStyle(.red)
                        .lineLimit(2)
                    Button("Erneut versuchen") {
                        enrollError = nil
                        downloadStatus = nil
                        flowStatus = nil
                        localPath = nil
                        downloadProfile()
                    }
                    .buttonStyle(.bordered)
                }
            } else if enrollmentReady {
                Text("Enrollment bestätigt. Weiterleitung läuft automatisch …")
                    .font(.callout)
                    .foregroundStyle(.secondary)
            } else {
                Text("Bitte kurz warten …")
                    .font(.callout)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private func startIfNeeded() {
        if localPath == nil && !busy && !enrollmentReady && enrollError == nil {
            downloadProfile()
        }
    }

    private func downloadProfile() {
        let dest = "/tmp/rebreak-enrollment.mobileconfig"
        let udid = model.device?.udid
        busy = true
        downloadStatus = "Lade von mdm.rebreak.org …"
        Task {
            do {
                guard let url = URL(string: "https://mdm.rebreak.org/enrollment/rebreak-enrollment.mobileconfig") else {
                    throw URLError(.badURL)
                }
                var request = URLRequest(url: url)
                request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
                request.setValue("no-cache", forHTTPHeaderField: "Cache-Control")
                request.setValue("no-cache", forHTTPHeaderField: "Pragma")
                let (data, response) = try await URLSession.shared.data(for: request)
                guard let http = response as? HTTPURLResponse else {
                    throw URLError(.badServerResponse)
                }
                guard http.statusCode == 200 else {
                    let body = String(data: data, encoding: .utf8)?.prefix(200) ?? ""
                    throw NSError(domain: "RebreakMDM", code: http.statusCode, userInfo: [
                        NSLocalizedDescriptionKey: "MDM-Server hat Status \(http.statusCode) zurückgegeben. \(body)"
                    ])
                }
                // Subject-Substitution: iOS ersetzt %SerialNumber%/%UDID% nur bei
                // DEP-installed Profilen, NICHT bei Safari/AirDrop. Wir patchen
                // die Variablen lokal mit der echten UDID, damit jeder Device-Bind
                // einen eindeutigen DN beim SCEP-Server erzeugt.
                var profileData = data
                if let udid, var text = String(data: data, encoding: .utf8) {
                    text = text.replacingOccurrences(of: "%SerialNumber%", with: udid)
                    text = text.replacingOccurrences(of: "%UDID%", with: udid)
                    if let patched = text.data(using: .utf8) {
                        profileData = patched
                    }
                }
                try profileData.write(to: URL(fileURLWithPath: dest))
                await MainActor.run {
                    localPath = dest
                    downloadStatus = "Geladen: \(dest) (\(profileData.count) Bytes)"
                }
                await MainActor.run {
                    runInstallFlow(path: dest)
                }
            } catch {
                await MainActor.run {
                    busy = false
                    downloadStatus = "Download fehlgeschlagen: \(error.localizedDescription)"
                    enrollError = "MDM-Server nicht erreichbar (\(error.localizedDescription)). Bitte später erneut versuchen."
                }
            }
        }
    }

    private func runInstallFlow(path: String) {
        guard !enrollmentReady else { return }
        flowStatus = "Versuche automatische Installation via USB …"
        Task {
            var installSucceeded = false
            var shouldPollEnrollment = false

            for attempt in 1...3 {
                do {
                    try await DeviceDetector.installProfileSilently(path: path)
                    installSucceeded = true
                    shouldPollEnrollment = true
                    await MainActor.run {
                        flowStatus = "✓ Profil wurde übertragen. Prüfe Installation + Enrollment …"
                    }
                    break
                } catch DeviceDetector.DetectorError.deviceLocked {
                    if attempt < 3 {
                        await MainActor.run {
                            flowStatus = "iPhone ist gesperrt. Retry \(attempt)/2 … bitte entsperren."
                        }
                        try? await Task.sleep(for: .seconds(3))
                        continue
                    }
                    await MainActor.run {
                        busy = false
                        flowStatus = "iPhone weiter gesperrt. Bitte entsperren und erneut versuchen."
                        showUnlockModal = true
                    }
                    return
                } catch DeviceDetector.DetectorError.profileUserInteractionRequired {
                    shouldPollEnrollment = true
                    await MainActor.run {
                        flowStatus = "Bitte am iPhone Profil bestätigen. Wir prüfen danach automatisch weiter …"
                    }
                    break
                } catch {
                    await MainActor.run {
                        flowStatus = "iOS verlangt Bestätigung am Gerät: \(error.localizedDescription)"
                    }
                    break
                }
            }

            if installSucceeded || shouldPollEnrollment {
                await waitForEnrollmentReady()
            } else {
                await MainActor.run {
                    busy = false
                }
            }
        }
    }

    private func waitForEnrollmentReady() async {
        pollTask?.cancel()
        let task = Task {
            for _ in 0..<40 {
                let profiles = await DeviceDetector.installedProfileIDs()
                let hasProfile = profiles.contains(enrollmentProfileID)
                let isBackendEnrolled = await checkBackendEnrolled()
                if hasProfile, isBackendEnrolled {
                    await MainActor.run {
                        busy = false
                        enrollmentReady = true
                        model.device?.isEnrolled = true
                        flowStatus = "✓ Profil aktiv und Server-Enrollment bestätigt."
                        triggerAutomaticContinue()
                    }
                    return
                }
                if hasProfile {
                    await MainActor.run {
                        flowStatus = "Profil aktiv. Warte auf Enrollment-Check-In am Server …"
                    }
                }
                try? await Task.sleep(for: .seconds(3))
            }
            await MainActor.run {
                busy = false
                flowStatus = "⚠ Enrollment noch nicht vollständig bestätigt. Bitte iPhone-Profil-Dialog prüfen."
            }
        }
        pollTask = task
        _ = await task.result
    }

    private func checkBackendEnrolled() async -> Bool {
        guard let udid = model.device?.udid else { return false }
        guard let status = try? await MDMStatus.query(udid: udid) else { return false }
        await MainActor.run {
            model.device?.enrollmentStatus = status
            if status.isEnrolled {
                model.device?.isEnrolled = true
            }
        }
        return status.isEnrolled
    }

    @MainActor
    private func triggerAutomaticContinue() {
        guard enrollmentReady, !didAutoAdvance else { return }
        didAutoAdvance = true
        Task { @MainActor in
            try? await Task.sleep(for: .seconds(0.8))
            model.goTo(.configure)
        }
    }
}
