import SwiftUI
import WebKit

/// Visible WKWebView that loads route-explorer.com so Cloudflare Turnstile
/// has a real-looking browser session to fingerprint. Cookies persist in
/// `WKWebsiteDataStore.default()` — the same store `WebViewFetcher` uses —
/// so once the user clears the gate, every subsequent `/api/flight-search`
/// call carries `am_clearance` automatically.
///
/// The sheet polls `/api/token` from inside the WebView once per second.
/// When it returns 200 (clearance achieved), the sheet auto-dismisses.
struct RouteExplorerGateSheet: View {
    /// Set to true when /api/token returns 200 from inside the WebView.
    @State private var cleared = false
    @State private var statusLine = "Loading route-explorer…"
    @State private var attempts = 0
    @Environment(\.dismiss) private var dismiss

    init() {
        DiagnosticLogger.shared.log("GATE", "sheetOpened", [:])
    }

    var body: some View {
        NavigationStack {
            ZStack(alignment: .top) {
                GateWebView(
                    onTokenStatus: { status in
                        attempts += 1
                        DiagnosticLogger.shared.log("GATE", "probe", [
                            "tick": attempts,
                            "status": status,
                        ])
                        if status == 200 {
                            statusLine = "Cleared ✓"
                            cleared = true
                            DiagnosticLogger.shared.log("GATE", "cleared", [
                                "afterTicks": attempts,
                            ])
                            // Brief beat so the user sees the success,
                            // then dismiss back into the search.
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                                dismiss()
                            }
                        } else {
                            statusLine = "Verifying… (probe #\(attempts), HTTP \(status))"
                        }
                    }
                )

                VStack(spacing: 0) {
                    HStack {
                        Image(systemName: cleared
                            ? "checkmark.seal.fill"
                            : "shield.lefthalf.filled")
                            .foregroundStyle(cleared ? .green : .orange)
                        Text(statusLine)
                            .font(.footnote.monospaced())
                            .lineLimit(1)
                            .truncationMode(.middle)
                        Spacer()
                    }
                    .padding(.horizontal, 12)
                    .padding(.vertical, 8)
                    .background(.regularMaterial)
                }
            }
            .navigationTitle("Verify route-explorer")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Skip") { dismiss() }
                }
            }
        }
        .interactiveDismissDisabled(false)
    }
}

// MARK: - UIViewRepresentable

private struct GateWebView: UIViewRepresentable {
    let onTokenStatus: (Int) -> Void

    func makeCoordinator() -> Coordinator {
        Coordinator(onTokenStatus: onTokenStatus)
    }

    func makeUIView(context: Context) -> WKWebView {
        let config = WKWebViewConfiguration()
        config.websiteDataStore = .default()
        let view = WKWebView(frame: .zero, configuration: config)
        view.navigationDelegate = context.coordinator
        view.customUserAgent =
            "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) " +
            "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 " +
            "Mobile/15E148 Safari/604.1"
        view.load(URLRequest(url: URL(string: "https://route-explorer.com/")!))
        context.coordinator.attach(view)
        return view
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {}

    final class Coordinator: NSObject, WKNavigationDelegate {
        let onTokenStatus: (Int) -> Void
        private weak var webView: WKWebView?
        private var pollTimer: Timer?
        private var isPolling = false

        init(onTokenStatus: @escaping (Int) -> Void) {
            self.onTokenStatus = onTokenStatus
        }

        func attach(_ webView: WKWebView) {
            self.webView = webView
        }

        deinit {
            pollTimer?.invalidate()
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            startPolling()
        }

        private func startPolling() {
            guard pollTimer == nil else { return }
            pollTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
                guard let self else { return }
                self.probeToken()
            }
        }

        private func probeToken() {
            guard let webView, !isPolling else { return }
            isPolling = true
            let js = """
            return await new Promise((res) => {
                fetch('/api/token', { credentials: 'include' })
                    .then(r => res(r.status))
                    .catch(() => res(-1));
            });
            """
            Task { @MainActor in
                let value = try? await webView.callAsyncJavaScript(js, contentWorld: .page)
                let status = (value as? Int) ?? -1
                self.onTokenStatus(status)
                // Snapshot cookies on the shared data store so we can
                // tell whether `rex_clearance` ever landed.
                let cookies = await WKWebsiteDataStore.default()
                    .httpCookieStore.allCookies()
                let reCookies = cookies.filter { $0.domain.contains("route-explorer.com") }
                DiagnosticLogger.shared.log("GATE", "cookieSnapshot", [
                    "count": reCookies.count,
                    "names": reCookies.map { $0.name }.sorted().joined(separator: ","),
                    "hasRexClearance": reCookies.contains { $0.name == "rex_clearance" },
                ])
                if status == 200 {
                    self.pollTimer?.invalidate()
                    self.pollTimer = nil
                }
                self.isPolling = false
            }
        }
    }
}
