'use client';

// The AI Assistant's entry point in the MAIN mail view — a Sparkles button in
// the search toolbar that opens a compact Ask dialog. Until this existed, the
// only way to ask the assistant anything was the "Try it" box buried in
// Settings → AI Assistant, which is a configuration screen, not a workflow.
//
// Deliberately reuses the exact same wire client (lib/ai/local-client's
// askMail) and the exact same persisted provider settings as the Settings
// pane — this is a second door to the same room, not a second room. When no
// provider is configured yet, the dialog deep-links to the Settings pane
// (where local-discovery offers the one-click Connect) instead of duplicating
// that setup flow here.

import { useCallback, useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { AlertTriangle, Loader2, Settings2, Sparkles, X } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { apiFetch } from '@/lib/browser-navigation';
import { useAccountStore } from '@/stores/account-store';
import { DEFAULT_AI_POLICY, type AiPolicy } from '@/lib/ai/types';
import { supportsLocalLlm } from '@/lib/platform-capabilities';
import { getAiApiKey } from '@/lib/ai/key-store';
import { loadAiSettings, isPresetActiveId, presetIdFromActiveId, type AiLocalSettings } from '@/lib/ai/local-settings';
import { askMail, type AskResult } from '@/lib/ai/local-client';
import { ensureDefaultProvider } from '@/lib/ai/auto-provision';

function useAiPolicy(): { policy: AiPolicy; loaded: boolean } {
  const [policy, setPolicy] = useState<AiPolicy>(DEFAULT_AI_POLICY);
  const [loaded, setLoaded] = useState(false);
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const res = await apiFetch('/api/ai/policy');
        if (res.ok && !cancelled) setPolicy(await res.json());
      } catch {
        /* stays at DEFAULT (disabled) — the button simply doesn't render */
      } finally {
        if (!cancelled) setLoaded(true);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);
  return { policy, loaded };
}

/** Mirrors the Settings pane's canAsk gating: is any provider actually ready? */
function providerConfigured(settings: AiLocalSettings, policy: AiPolicy): boolean {
  const classes = policy.entitlement.classes;
  switch (settings.provider) {
    case 'local':
      return supportsLocalLlm() && classes.includes('local') && !!settings.localModel;
    case 'server':
      return classes.includes('server') && !!settings.serverModel;
    case 'opencode':
      return classes.includes('opencode') && !!settings.opencodeModel;
    case 'public': {
      if (isPresetActiveId(settings.activeProfileId)) {
        return classes.includes('public') && !!presetIdFromActiveId(settings.activeProfileId) && settings.publicConsentAccepted;
      }
      const active = settings.publicProfiles.find((p) => p.id === settings.activeProfileId) ?? null;
      return classes.includes('public') && !!active && settings.publicConsentAccepted;
    }
    default:
      return false;
  }
}

export function AiAskButton() {
  const router = useRouter();
  const { policy, loaded } = useAiPolicy();
  // Retrieval must read the SAME account slot the indexer wrote under.
  const activeSlot = useAccountStore((s) => s.accounts.find((a) => a.id === s.activeAccountId)?.cookieSlot);
  const [open, setOpen] = useState(false);
  // Re-read on every open: the user may have just configured a provider in
  // Settings and come straight back here — a mount-time snapshot would still
  // say "not configured".
  const [settings, setSettings] = useState<AiLocalSettings>(() => loadAiSettings());

  const [question, setQuestion] = useState('');
  const [asking, setAsking] = useState(false);
  const [askResult, setAskResult] = useState<AskResult | null>(null);
  const [askError, setAskError] = useState<string | null>(null);
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const openDialog = useCallback(() => {
    setSettings(loadAiSettings());
    setAskResult(null);
    setAskError(null);
    setOpen(true);
  }, []);

  // Zero-config default (see lib/ai/auto-provision.ts): resolves as soon as
  // policy loads, so a user who never visits Settings still finds AI
  // already on the first time they open this dialog, if OpenCode or Ollama
  // is available.
  useEffect(() => {
    if (!loaded) return;
    (async () => {
      const next = await ensureDefaultProvider(policy);
      setSettings(next);
    })();
  }, [loaded, policy]);

  useEffect(() => {
    if (!open) return;
    textareaRef.current?.focus();
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setOpen(false);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);

  const configured = providerConfigured(settings, policy);
  const canAsk = configured && question.trim().length > 0 && !asking;

  const runAsk = useCallback(async () => {
    if (!canAsk) return;
    setAsking(true);
    setAskError(null);
    setAskResult(null);
    try {
      const managedPresetId = presetIdFromActiveId(settings.activeProfileId);
      const activeProfile = managedPresetId ? null : settings.publicProfiles.find((p) => p.id === settings.activeProfileId) ?? null;
      const key = activeProfile ? getAiApiKey(activeProfile.id) : null;
      const result = await askMail(question.trim(), {
        provider: settings.provider as 'local' | 'server' | 'public' | 'opencode',
        localBaseUrl: settings.localBaseUrl,
        localModel: settings.localModel,
        serverModel: settings.serverModel,
        opencodeModel: settings.opencodeModel,
        slot: activeSlot,
        publicProfile: activeProfile && key ? { baseUrl: activeProfile.baseUrl, model: activeProfile.model, apiKey: key } : null,
        publicPresetId: managedPresetId,
      });
      setAskResult(result);
    } catch (err) {
      setAskError(err instanceof Error ? err.message : String(err));
    } finally {
      setAsking(false);
    }
  }, [canAsk, question, settings, activeSlot]);

  const goToSettings = useCallback(() => {
    // The Settings page's one-shot deep-link channel (see readPersistedTab in
    // app/(main)/[locale]/settings/page.tsx) — lands directly on the AI pane,
    // where local-discovery's Connect banner does the actual setup.
    try {
      sessionStorage.setItem('settings-deep-link-tab', 'ai_assistant');
    } catch {
      /* private mode — the settings page just opens on its default tab */
    }
    setOpen(false);
    router.push('/settings');
  }, [router]);

  // Hidden entirely when the admin gate is off or no provider class is
  // allowed — same visibility rule as the Settings pane itself.
  if (!loaded || !policy.enabled || policy.entitlement.classes.length === 0) return null;

  return (
    <>
      <button
        type="button"
        onClick={openDialog}
        className="flex-shrink-0 p-2 rounded-md transition-colors text-muted-foreground hover:text-foreground hover:bg-muted"
        title="AI Assistant"
        aria-label="AI Assistant"
        data-tour="ai-assistant"
      >
        <Sparkles className="w-4 h-4" />
      </button>

      {open && (
        <div
          className="fixed inset-0 z-50 flex items-start justify-center bg-black/50 p-4 pt-[10vh]"
          onMouseDown={(e) => {
            if (e.target === e.currentTarget) setOpen(false);
          }}
          role="dialog"
          aria-modal="true"
          aria-label="AI Assistant"
        >
          <div className="w-full max-w-xl rounded-xl border border-border bg-popover text-popover-foreground shadow-2xl">
            <div className="flex items-center justify-between border-b border-border px-4 py-3">
              <div className="flex items-center gap-2">
                <Sparkles className="w-4 h-4 text-primary" />
                <h2 className="text-sm font-semibold">AI Assistant</h2>
              </div>
              <button
                type="button"
                onClick={() => setOpen(false)}
                className="p-1 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
                aria-label="Close"
              >
                <X className="w-4 h-4" />
              </button>
            </div>

            <div className="flex flex-col gap-3 p-4">
              {!configured ? (
                <>
                  <p className="text-sm text-muted-foreground">
                    No AI provider is set up yet. Pick one in Settings — if Ollama is running on this machine, a
                    one-click Connect is waiting there.
                  </p>
                  <div>
                    <Button size="sm" onClick={goToSettings}>
                      <Settings2 className="w-3.5 h-3.5 me-1.5" />
                      Open AI settings
                    </Button>
                  </div>
                </>
              ) : (
                <>
                  <textarea
                    ref={textareaRef}
                    value={question}
                    onChange={(e) => setQuestion(e.target.value)}
                    onKeyDown={(e) => {
                      if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') void runAsk();
                    }}
                    rows={3}
                    placeholder="Ask a question about your mail…"
                    className="w-full px-3 py-2 text-sm rounded-md bg-muted border border-border text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors duration-150 resize-y"
                  />
                  <div className="flex items-center gap-3">
                    <Button size="sm" onClick={() => void runAsk()} disabled={!canAsk}>
                      {asking && <Loader2 className="w-3.5 h-3.5 me-1.5 animate-spin" />}
                      Ask
                    </Button>
                    <span className="text-xs text-muted-foreground">⌘⏎ to send</span>
                  </div>

                  {askError && (
                    <div className="flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/5 p-3">
                      <AlertTriangle className="w-4 h-4 mt-0.5 text-destructive shrink-0" />
                      <p className="text-sm text-destructive">{askError}</p>
                    </div>
                  )}

                  {askResult && (
                    <div className={cn('flex flex-col gap-2 rounded-lg border border-border p-4', 'max-h-[45vh] overflow-y-auto')}>
                      {askResult.retrievalState === 'no-index' && (
                        <p className="text-xs text-muted-foreground italic">
                          No local mail index available in this session — answered without your mail.
                        </p>
                      )}
                      {askResult.retrievalState === 'no-match' && (
                        <p className="text-xs text-muted-foreground italic">
                          Your mail index is available, but nothing in it matched this question — answered
                          without your mail. It matches on keywords, so content questions work better than
                          recency ones.
                        </p>
                      )}
                      <p className="text-sm text-foreground whitespace-pre-wrap">{askResult.answer}</p>
                      {askResult.sources.length > 0 && (
                        <div className="flex flex-col gap-0.5 border-t border-border pt-2 mt-1">
                          <span className="text-xs font-medium text-muted-foreground">Sources</span>
                          {askResult.sources.map((s, i) => (
                            <span key={s.id} className="text-xs text-muted-foreground truncate">
                              [{i + 1}] {s.subject}
                            </span>
                          ))}
                        </div>
                      )}
                    </div>
                  )}
                </>
              )}
            </div>
          </div>
        </div>
      )}
    </>
  );
}
