import AppKit
import Combine
import SwiftUI
import WebKit

private extension Notification.Name {
    /// Posted when Translate’s web view finishes loading (object: `WKWebView`).
    static let translateWidgetPageLoaded = Notification.Name("google_apps.translateWidgetPageLoaded")
}

/// Holds the embedded translator `WKWebView` so toolbar actions (voice, conversation JS) can target it.
private final class TranslateWebViewRef: ObservableObject {
    weak var webView: WKWebView?
}

/// Large interactive Google Translate: full web UI in-panel (text, mic, conversation, history) plus local recent chips.
struct TranslateDesktopWidgetView: View {
    let app: LauncherApp
    let mode: TranslateWidgetMode
    var isPreview: Bool = false

    @StateObject private var webRef = TranslateWebViewRef()
    @State private var webURL: URL
    @State private var recentEntries: [TranslateRecentEntry] = []

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

    private static let recentDefaultsKey = "translateWidgetRecentJSON"

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

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

    private var interactiveBody: some View {
        Group {
            if isPreview {
                translatePreviewChrome
            } else {
                translateLiveChrome
            }
        }
    }

    private var translatePreviewChrome: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 22, style: .continuous)
                .fill(
                    LinearGradient(
                        colors: [Color(red: 0.2, green: 0.45, blue: 0.95), Color(red: 0.08, green: 0.22, blue: 0.55)],
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                )
            VStack(spacing: 12) {
                AppIconView(app: app, size: 48, showAppBackground: false, iconPaddingFactor: 0.08)
                Text("Google Translate")
                    .font(.system(size: 15, weight: .bold))
                    .foregroundStyle(.white.opacity(0.92))
                Text("Type, translate documents, and browse history — all inside this widget.")
                    .font(.system(size: 11, weight: .medium))
                    .foregroundStyle(.white.opacity(0.7))
                    .multilineTextAlignment(.center)
                    .padding(.horizontal, 8)
            }
            .padding(16)
        }
    }

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

            VStack(spacing: 0) {
                translateToolbar
                recentStrip
                TranslateWebWidgetView(url: $webURL, webRef: webRef)
                    .frame(minHeight: 320)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
            }
            .padding(10)
        }
        .onReceive(NotificationCenter.default.publisher(for: .translateWidgetPageLoaded)) { note in
            guard let wv = note.object as? WKWebView, wv === webRef.webView else { return }
            extractAndMergeRecents(webView: wv)
        }
    }

    private var translateToolbar: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack(spacing: 8) {
                AppIconView(app: app, size: 28, showAppBackground: false, iconPaddingFactor: 0.08)
                Text("Translate")
                    .font(.system(size: 14, weight: .bold))
                    .foregroundStyle(.white.opacity(0.95))
                Spacer(minLength: 0)
                Button(action: {
                    NSApp.activate(ignoringOtherApps: true)
                    openInAppBrowser(baseURL)
                }) {
                    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 Translate in browser")
            }

            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 8) {
                    toolbarChip("Text", systemImage: "textformat", path: "/?sl=auto&tl=en", action: nil)
                    toolbarChip("Documents", systemImage: "doc.text", path: "/?tr=f&hl=en&tab=wT", action: nil)
                    toolbarChip("History", systemImage: "clock.arrow.circlepath", path: nil, action: { runOpenHistory() })
                }
            }
        }
        .padding(.horizontal, 6)
        .padding(.vertical, 8)
        .background(
            RoundedRectangle(cornerRadius: 16, style: .continuous)
                .fill(Color(red: 0.08, green: 0.14, blue: 0.28))
        )
        .zIndex(20)
    }

    @ViewBuilder
    private var recentStrip: some View {
        if recentEntries.isEmpty {
            EmptyView()
        } else {
            VStack(alignment: .leading, spacing: 4) {
                Text("Recent")
                    .font(.system(size: 10, weight: .bold))
                    .foregroundStyle(.white.opacity(0.55))
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(recentEntries) { entry in
                            Button(action: {
                                NSApp.activate(ignoringOtherApps: true)
                                applyRecentEntry(entry)
                            }) {
                                VStack(alignment: .leading, spacing: 2) {
                                    Text(entry.sourcePreview)
                                        .font(.system(size: 10, weight: .semibold))
                                        .foregroundStyle(.white.opacity(0.95))
                                        .lineLimit(1)
                                    Text(entry.targetPreview)
                                        .font(.system(size: 9, weight: .medium))
                                        .foregroundStyle(.white.opacity(0.6))
                                        .lineLimit(1)
                                }
                                .padding(.horizontal, 10)
                                .padding(.vertical, 6)
                                .background(Capsule().fill(Color.white.opacity(0.1)))
                            }
                            .buttonStyle(.plain)
                        }
                    }
                }
            }
            .padding(.horizontal, 6)
            .padding(.bottom, 6)
        }
    }

    private func toolbarChip(
        _ title: String,
        systemImage: String,
        path: String?,
        action: (() -> Void)?
    ) -> some View {
        Button(action: {
            NSApp.activate(ignoringOtherApps: true)
            if let action {
                action()
            } else if let path {
                navigateWeb(to: path)
            }
        }) {
            HStack(spacing: 4) {
                Image(systemName: systemImage)
                    .font(.system(size: 11, weight: .semibold))
                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: - URLs & actions

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

    private func openInAppBrowser(_ url: URL) {
        InAppBrowserWindowManager.shared.open(url: url, title: app.name)
    }

    private func runOpenHistory() {
        guard let wv = webRef.webView else { return }
        wv.evaluateJavaScript(Self.clickHistoryJavaScript, completionHandler: nil)
    }

    private func applyRecentEntry(_ entry: TranslateRecentEntry) {
        navigateWeb(to: "/?sl=auto&tl=en")
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
            guard let wv = webRef.webView else { return }
            guard let jsonData = try? JSONEncoder().encode([entry.source]),
                  let jsonLiteral = String(data: jsonData, encoding: .utf8)
            else { return }
            let script = """
            (function(){
              var arr = \(jsonLiteral);
              var text = arr[0] || '';
              var ta = document.querySelector('textarea');
              if (!ta) return;
              ta.focus();
              ta.value = text;
              ta.dispatchEvent(new Event('input', { bubbles: true }));
              ta.dispatchEvent(new Event('change', { bubbles: true }));
            })();
            """
            wv.evaluateJavaScript(script, completionHandler: nil)
        }
    }

    // MARK: - Recent translations (local)

    private func loadRecents() {
        guard let data = UserDefaults.standard.string(forKey: Self.recentDefaultsKey)?.data(using: .utf8),
              let decoded = try? JSONDecoder().decode([TranslateRecentEntry].self, from: data)
        else {
            recentEntries = []
            return
        }
        recentEntries = decoded
    }

    private func saveRecents() {
        guard let data = try? JSONEncoder().encode(recentEntries),
              let str = String(data: data, encoding: .utf8)
        else { return }
        UserDefaults.standard.set(str, forKey: Self.recentDefaultsKey)
    }

    private func extractAndMergeRecents(webView: WKWebView) {
        webView.evaluateJavaScript(Self.extractPairJavaScript) { result, _ in
            Task { @MainActor in
                guard let json = result as? String,
                      let data = json.data(using: .utf8),
                      let pair = try? JSONDecoder().decode(ExtractedPair.self, from: data),
                      pair.source.count > 0,
                      pair.target.count > 1
                else { return }

                var next = recentEntries
                if let idx = next.firstIndex(where: { $0.source == pair.source }) {
                    next[idx] = TranslateRecentEntry(
                        id: next[idx].id,
                        source: pair.source,
                        target: pair.target,
                        savedAt: Date()
                    )
                } else {
                    let entry = TranslateRecentEntry(id: UUID(), source: pair.source, target: pair.target, savedAt: Date())
                    next.insert(entry, at: 0)
                }
                if next.count > 8 {
                    next = Array(next.prefix(8))
                }
                recentEntries = next
                saveRecents()
            }
        }
    }

    private struct ExtractedPair: Decodable {
        var source: String
        var target: String
    }

    private static let extractPairJavaScript = #"""
(function(){
  try {
    var tas = document.querySelectorAll('textarea');
    var src = '';
    var dst = '';
    if (tas.length >= 1) src = (tas[0].value || tas[0].innerText || '').trim();
    if (tas.length >= 2) dst = (tas[1].value || tas[1].innerText || '').trim();
    if (!dst) {
      var main = document.querySelector('[role="main"]');
      if (main) {
        var spans = main.querySelectorAll('span[lang], span[jsname]');
        if (spans.length) {
          var parts = [];
          for (var i = 0; i < Math.min(spans.length, 6); i++) {
            var t = (spans[i].innerText || '').trim();
            if (t) parts.push(t);
          }
          dst = parts.join(' ').trim();
        }
      }
    }
    return JSON.stringify({ source: src, target: dst });
  } catch (e) {
    return JSON.stringify({ source: '', target: '' });
  }
})();
"""#

    private static let clickHistoryJavaScript = #"""
(function(){
  var nodes = document.querySelectorAll('button, [role="tab"], a, div[role="button"]');
  for (var i = 0; i < nodes.length; i++) {
    var b = nodes[i];
    var t = (b.innerText || b.getAttribute('aria-label') || '') + '';
    if (/^history$/i.test(t.trim()) || /translation\s+history/i.test(t)) { b.click(); return 'ok'; }
  }
  return 'no';
})();
"""#
}

private struct TranslateRecentEntry: Codable, Identifiable, Equatable {
    var id: UUID
    var source: String
    var target: String
    var savedAt: Date

    var sourcePreview: String {
        String(source.prefix(42))
    }

    var targetPreview: String {
        String(target.prefix(42))
    }
}

// MARK: - WKWebView

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

private struct TranslateWebWidgetView: NSViewRepresentable {
    @Binding var url: URL
    var webRef: TranslateWebViewRef

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

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

        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
        webRef.webView = wv
        context.coordinator.lastLoadedURLString = url.absoluteString
        wv.load(URLRequest(url: url))
        DispatchQueue.main.async {
            Self.stripWebKitOuterChrome(wv)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
            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?
        let webRef: TranslateWebViewRef

        init(webRef: TranslateWebViewRef) {
            self.webRef = webRef
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            self.webView = webView
            webRef.webView = webView
            TranslateWebWidgetView.stripWebKitOuterChrome(webView)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) {
                TranslateWebWidgetView.stripWebKitOuterChrome(webView)
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) {
                NotificationCenter.default.post(name: .translateWidgetPageLoaded, object: webView)
            }
        }
    }
}
