import AppKit
import SwiftUI
import WebKit

/// Google Keep desktop widget: recent notes (small) or embedded Keep (large).
struct KeepDesktopWidgetView: View {
    let app: LauncherApp
    let mode: KeepWidgetMode
    var isPreview: Bool = false

    @ObservedObject private var liveNotes = KeepLiveNotesStore.shared

    private var baseURL: URL { app.webURL ?? URL(string: "https://keep.google.com")! }

    var body: some View {
        Group {
            switch mode {
            case .compact:
                compactBody
            case .interactive:
                interactiveBody
            }
        }
        .clipShape(RoundedRectangle(cornerRadius: 22, style: .continuous))
    }

    // MARK: - Small

    /// Static rows for widget gallery / preview only.
    private static let previewCatalogNotes: [KeepLiveNotesStore.Note] = [
        KeepLiveNotesStore.Note(id: "p1", title: "Groceries", snippet: "Milk, eggs, coffee…"),
        KeepLiveNotesStore.Note(id: "p2", title: "Meeting notes", snippet: "Follow up with design…"),
        KeepLiveNotesStore.Note(id: "p3", title: "Ideas", snippet: "Widget themes for spring…"),
    ]

    private var compactDisplayNotes: [KeepLiveNotesStore.Note] {
        if isPreview { return Array(Self.previewCatalogNotes.prefix(3)) }
        return Array(liveNotes.notes.prefix(3))
    }

    private var compactBody: some View {
        ZStack(alignment: .topLeading) {
            keepGradientBackground
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            VStack(alignment: .leading, spacing: 10) {
                HStack(spacing: 10) {
                    AppIconView(app: app, size: 32, showAppBackground: false, iconPaddingFactor: 0.08)
                    VStack(alignment: .leading, spacing: 2) {
                        Text(app.name)
                            .font(.system(size: 14, weight: .bold))
                            .foregroundStyle(.white.opacity(0.95))
                        Text("Recent")
                            .font(.system(size: 10, weight: .semibold))
                            .foregroundStyle(.white.opacity(0.65))
                    }
                    Spacer(minLength: 0)
                    if !isPreview {
                        Button(action: {
                            NSApp.activate(ignoringOtherApps: true)
                            liveNotes.forceRefresh()
                        }) {
                            Image(systemName: "arrow.clockwise")
                                .font(.system(size: 12, weight: .semibold))
                                .foregroundStyle(.white.opacity(0.75))
                        }
                        .buttonStyle(.plain)
                        .help("Refresh from Keep")
                    }
                }
                keepStatusCaption

                compactNoteList

                keepPrimaryButton(title: "New note", systemImage: "square.and.pencil") {
                    openKeepFragment("NOTE")
                }
            }
            .padding(14)
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
        .disabled(isPreview)
        .opacity(isPreview ? 0.85 : 1)
        .onAppear {
            if !isPreview {
                liveNotes.requestRefreshIfNeeded()
            }
        }
    }

    @ViewBuilder
    private var keepStatusCaption: some View {
        if isPreview {
            Text("Preview")
                .font(.system(size: 9, weight: .bold))
                .foregroundStyle(.white.opacity(0.45))
        } else {
            switch liveNotes.phase {
            case .idle, .loading:
                HStack(spacing: 6) {
                    ProgressView()
                        .controlSize(.small)
                        .scaleEffect(0.75)
                    Text("Loading from Keep…")
                        .font(.system(size: 9, weight: .medium))
                        .foregroundStyle(.white.opacity(0.55))
                }
            case .ready:
                Text("From your Keep")
                    .font(.system(size: 9, weight: .bold))
                    .foregroundStyle(.white.opacity(0.5))
            case .empty:
                Text("No notes found")
                    .font(.system(size: 9, weight: .medium))
                    .foregroundStyle(.white.opacity(0.55))
            case .needsSignIn:
                Text("Sign in via large Keep widget")
                    .font(.system(size: 9, weight: .medium))
                    .foregroundStyle(Color(red: 1, green: 0.85, blue: 0.4).opacity(0.95))
                    .lineLimit(2)
            case .failed:
                Text("Could not load — tap refresh")
                    .font(.system(size: 9, weight: .medium))
                    .foregroundStyle(.white.opacity(0.55))
            }
        }
    }

    @ViewBuilder
    private var compactNoteList: some View {
        if !isPreview, case .needsSignIn = liveNotes.phase {
            Text("Open the large Keep widget and sign in to Google. This widget reads notes from the same session as that web view.")
                .font(.system(size: 10, weight: .medium))
                .foregroundStyle(.white.opacity(0.72))
                .fixedSize(horizontal: false, vertical: true)
        } else if compactDisplayNotes.isEmpty, !isPreview, liveNotes.phase == .ready || liveNotes.phase == .empty {
            Text("No notes yet, or Keep changed its layout. Try refresh or open Keep in the large widget.")
                .font(.system(size: 10, weight: .medium))
                .foregroundStyle(.white.opacity(0.65))
                .fixedSize(horizontal: false, vertical: true)
        } else {
            VStack(alignment: .leading, spacing: 8) {
                ForEach(compactDisplayNotes) { note in
                    VStack(alignment: .leading, spacing: 4) {
                        Text(note.title.isEmpty ? "Note" : note.title)
                            .font(.system(size: 12, weight: .bold))
                            .foregroundStyle(.white.opacity(0.95))
                            .lineLimit(1)
                        Text(note.snippet.isEmpty ? " " : note.snippet)
                            .font(.system(size: 10, weight: .medium))
                            .foregroundStyle(.white.opacity(0.65))
                            .lineLimit(2)
                    }
                    .padding(10)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(RoundedRectangle(cornerRadius: 12, style: .continuous).fill(Color.black.opacity(0.2)))
                }
            }
        }
    }

    // MARK: - Large (WKWebView)

    @State private var searchText = ""
    @State private var webURL: URL

    init(app: LauncherApp, mode: KeepWidgetMode, isPreview: Bool = false) {
        self.app = app
        self.mode = mode
        self.isPreview = isPreview
        let base = app.webURL ?? URL(string: "https://keep.google.com")!
        _webURL = State(initialValue: WidgetDeepLinkURL.resolved(base: base, actionPath: "/", accountSlot: 0))
    }

    private var interactiveBody: some View {
        Group {
            if isPreview {
                interactivePreviewChrome
            } else {
                interactiveLiveChrome
            }
        }
    }

    private var interactivePreviewChrome: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 22, style: .continuous)
                .fill(
                    LinearGradient(
                        colors: [Color(red: 0.42, green: 0.35, blue: 0.12), Color(red: 0.2, green: 0.18, blue: 0.1)],
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                )
            VStack(spacing: 12) {
                AppIconView(app: app, size: 48, showAppBackground: false, iconPaddingFactor: 0.08)
                Text("Google Keep")
                    .font(.system(size: 15, weight: .bold))
                    .foregroundStyle(.white.opacity(0.92))
                Text("Full Keep with notes, labels, and lists loads on your desktop.")
                    .font(.system(size: 11, weight: .medium))
                    .foregroundStyle(.white.opacity(0.65))
                    .multilineTextAlignment(.center)
                    .padding(.horizontal, 8)
            }
            .padding(16)
        }
    }

    private var interactiveLiveChrome: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 22, style: .continuous)
                .fill(Color.black.opacity(0.28))

            VStack(spacing: 0) {
                VStack(spacing: 8) {
                    interactiveHeader
                    interactiveSearchBar
                    filterChipsRow
                    createRow
                }
                .padding(.horizontal, 6)
                .padding(.vertical, 8)
                .background(
                    RoundedRectangle(cornerRadius: 16, style: .continuous)
                        .fill(Color(red: 0.12, green: 0.1, blue: 0.06))
                )
                .zIndex(20)

                KeepWebWidgetView(url: $webURL)
                    .frame(minHeight: 280)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
                    .zIndex(0)
            }
            .padding(10)
        }
    }

    private var interactiveHeader: some View {
        HStack(spacing: 8) {
            AppIconView(app: app, size: 28, showAppBackground: false, iconPaddingFactor: 0.08)
            Text("Keep")
                .font(.system(size: 14, weight: .bold))
                .foregroundStyle(.white.opacity(0.95))
            Spacer(minLength: 0)
            Button(action: {
                NSApp.activate(ignoringOtherApps: true)
                openKeepInBrowser()
            }) {
                Image(systemName: "arrow.up.right.square")
                    .font(.system(size: 13, weight: .semibold))
                    .foregroundStyle(.white.opacity(0.9))
                    .padding(8)
                    .background(Circle().fill(Color.white.opacity(0.12)))
            }
            .buttonStyle(.plain)
            .help("Open Keep in browser")
        }
    }

    private var interactiveSearchBar: some View {
        HStack(spacing: 8) {
            Image(systemName: "magnifyingglass")
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(.white.opacity(0.55))
            TextField("Search notes", text: $searchText)
                .textFieldStyle(.plain)
                .font(.system(size: 12, weight: .medium))
                .foregroundStyle(.white.opacity(0.95))
                .onSubmit { submitSearch() }
            Button("Go") { submitSearch() }
                .font(.system(size: 11, weight: .bold))
                .foregroundStyle(Color(red: 1, green: 0.85, blue: 0.35))
                .buttonStyle(.plain)
        }
        .padding(.horizontal, 10)
        .padding(.vertical, 8)
        .background(
            RoundedRectangle(cornerRadius: 10, style: .continuous)
                .fill(Color.white.opacity(0.08))
        )
    }

    private var filterChipsRow: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 8) {
                keepChip("Notes", fragment: "")
                keepChip("Reminders", fragment: "reminders")
                keepChip("Archive", fragment: "archive")
                keepChip("Trash", fragment: "trash")
                keepChip("Labels", fragment: "label")
            }
        }
    }

    private var createRow: some View {
        VStack(alignment: .leading, spacing: 6) {
            Text("Create")
                .font(.system(size: 10, weight: .bold))
                .foregroundStyle(.white.opacity(0.55))
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 8) {
                    createChip("Text", fragment: "NOTE")
                    createChip("List", fragment: "LIST")
                    createChip("Drawing", fragment: "DRAWING")
                    createChip("Image", fragment: "NOTE")
                    Button(action: {
                        NSApp.activate(ignoringOtherApps: true)
                        openKeepFragment("NOTE")
                    }) {
                        HStack(spacing: 4) {
                            Image(systemName: "photo")
                            Text("Photo")
                        }
                        .font(.system(size: 10, weight: .bold))
                        .foregroundStyle(.white.opacity(0.92))
                        .padding(.horizontal, 10)
                        .padding(.vertical, 6)
                        .background(Capsule().fill(Color.white.opacity(0.14)))
                    }
                    .buttonStyle(.plain)
                    .help("New note — add an image in Keep")
                }
            }
        }
    }

    private func keepChip(_ title: String, fragment: String) -> some View {
        Button(action: {
            NSApp.activate(ignoringOtherApps: true)
            if fragment.isEmpty {
                navigateWeb(to: "/")
            } else {
                navigateWeb(to: "/#\(fragment)")
            }
        }) {
            Text(title)
                .font(.system(size: 10, weight: .bold))
                .foregroundStyle(.white.opacity(0.92))
                .padding(.horizontal, 10)
                .padding(.vertical, 6)
                .background(Capsule().fill(Color.white.opacity(0.12)))
        }
        .buttonStyle(.plain)
    }

    private func createChip(_ title: String, fragment: String) -> some View {
        Button(action: {
            NSApp.activate(ignoringOtherApps: true)
            openKeepFragment(fragment)
        }) {
            Text(title)
                .font(.system(size: 10, weight: .bold))
                .foregroundStyle(.white.opacity(0.92))
                .padding(.horizontal, 10)
                .padding(.vertical, 6)
                .background(Capsule().fill(Color.white.opacity(0.12)))
        }
        .buttonStyle(.plain)
    }

    // MARK: - Shared styling

    private var keepGradientBackground: some View {
        LinearGradient(
            colors: [
                Color(red: 0.52, green: 0.42, blue: 0.14),
                Color(red: 0.22, green: 0.2, blue: 0.12),
            ],
            startPoint: .topLeading,
            endPoint: .bottomTrailing
        )
    }

    private func keepPrimaryButton(title: String, systemImage: String, action: @escaping () -> Void) -> some View {
        Button(action: {
            NSApp.activate(ignoringOtherApps: true)
            action()
        }) {
            HStack(spacing: 8) {
                Image(systemName: systemImage)
                    .font(.system(size: 13, weight: .semibold))
                Text(title)
                    .font(.system(size: 13, weight: .bold))
            }
            .foregroundStyle(Color(red: 0.12, green: 0.1, blue: 0.04))
            .frame(maxWidth: .infinity)
            .padding(.vertical, 11)
            .background(
                RoundedRectangle(cornerRadius: 12, style: .continuous)
                    .fill(Color.white.opacity(0.92))
            )
        }
        .buttonStyle(.plain)
        .disabled(isPreview)
        .allowsHitTesting(!isPreview)
    }

    // MARK: - URLs

    private func openKeepFragment(_ fragment: String) {
        guard !isPreview else { return }
        let url = WidgetDeepLinkURL.resolved(base: baseURL, actionPath: "/#\(fragment)", accountSlot: 0)
        InAppBrowserWindowManager.shared.open(url: url, title: app.name)
    }

    private func openKeepInBrowser() {
        guard !isPreview else { return }
        InAppBrowserWindowManager.shared.open(url: baseURL, title: app.name)
    }

    private func navigateWeb(to path: String) {
        let url = WidgetDeepLinkURL.resolved(base: baseURL, actionPath: path, accountSlot: 0)
        DispatchQueue.main.async {
            webURL = url
        }
    }

    private func submitSearch() {
        let q = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !q.isEmpty else { return }
        NSApp.activate(ignoringOtherApps: true)
        let encoded = q.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlFragmentAllowed) ?? q
        navigateWeb(to: "/#search/\(encoded)")
    }
}

// MARK: - WKWebView

private final class KeepWebViewClippingContainer: NSView {
    override var isFlipped: Bool { true }
}

private struct KeepWebWidgetView: NSViewRepresentable {
    @Binding var url: URL

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

    func makeNSView(context: Context) -> NSView {
        let container = KeepWebViewClippingContainer()
        container.wantsLayer = true
        container.layer?.masksToBounds = true
        container.layer?.cornerRadius = 12
        container.layer?.borderWidth = 0

        let config = WKWebViewConfiguration()
        config.defaultWebpagePreferences.allowsContentJavaScript = true
        let wv = WKWebView(frame: .zero, configuration: config)
        wv.translatesAutoresizingMaskIntoConstraints = false
        wv.focusRingType = .none
        wv.customUserAgent =
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15"
        wv.navigationDelegate = context.coordinator

        container.addSubview(wv)
        NSLayoutConstraint.activate([
            wv.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            wv.trailingAnchor.constraint(equalTo: container.trailingAnchor),
            wv.topAnchor.constraint(equalTo: container.topAnchor),
            wv.bottomAnchor.constraint(equalTo: container.bottomAnchor),
        ])

        context.coordinator.webView = wv
        context.coordinator.lastLoadedURLString = url.absoluteString
        wv.load(URLRequest(url: url))
        DispatchQueue.main.async {
            Self.stripWebKitOuterChrome(wv)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
            Self.stripWebKitOuterChrome(wv)
        }
        return container
    }

    func updateNSView(_ container: NSView, context: Context) {
        guard let wv = context.coordinator.webView else { return }
        let next = url.absoluteString
        guard context.coordinator.lastLoadedURLString != next else { return }
        context.coordinator.lastLoadedURLString = next
        wv.load(URLRequest(url: url))
    }

    private static func stripWebKitOuterChrome(_ webView: WKWebView) {
        webView.focusRingType = .none
        func walk(_ view: NSView) {
            view.focusRingType = .none
            view.layer?.borderWidth = 0
            view.layer?.borderColor = NSColor.clear.cgColor
            if let scroll = view as? NSScrollView {
                scroll.borderType = .noBorder
                scroll.drawsBackground = false
                scroll.scrollerStyle = .overlay
            }
            if let clip = view as? NSClipView {
                clip.drawsBackground = false
            }
            for sub in view.subviews {
                walk(sub)
            }
        }
        walk(webView)
    }

    final class Coordinator: NSObject, WKNavigationDelegate {
        weak var webView: WKWebView?
        var lastLoadedURLString: String?

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            KeepWebWidgetView.stripWebKitOuterChrome(webView)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
                KeepWebWidgetView.stripWebKitOuterChrome(webView)
            }
        }
    }
}
