'use client';

import { useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { CheckCircle2, Eye, EyeOff, Loader2, XCircle } from 'lucide-react';

import { PageHeader } from '@/components/shared/page-header';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { usePermissions } from '@/hooks/use-permissions';
import { apiFetch } from '@/lib/api/client';
import { AiBudgetCard } from '@/components/admin/ai-budget-card';

type Provider = 'openai' | 'claude';

interface ConfigResp {
  data: {
    provider: Provider;
    model: string;
    hasApiKey: boolean;
    useGlobal: boolean;
    aiEnabled: boolean;
    manualEntry: boolean;
  };
  models: Record<Provider, string[]>;
}

type Scope = 'port' | 'global';

interface SettingsBlockProps {
  scope: Scope;
  title: string;
  description: string;
  /** Hide the "use global" checkbox on the global tab. */
  showUseGlobal?: boolean;
}

function SettingsBlock(props: SettingsBlockProps) {
  const queryClient = useQueryClient();
  const queryKey = ['ocr-settings', props.scope];
  const { data, isLoading } = useQuery<ConfigResp>({
    queryKey,
    queryFn: () => apiFetch<ConfigResp>(`/api/v1/admin/ocr-settings?scope=${props.scope}`),
  });
  // Key the body on the loaded payload so useState initializers seed
  // from server values cleanly.
  const sig = data?.data
    ? `${data.data.provider}:${data.data.model}:${data.data.useGlobal}:${data.data.aiEnabled}:${data.data.manualEntry}`
    : 'loading';
  return (
    <SettingsBlockBody
      key={sig}
      {...props}
      data={data}
      isLoading={isLoading}
      queryClient={queryClient}
      queryKey={queryKey}
    />
  );
}

function SettingsBlockBody({
  scope,
  title,
  description,
  showUseGlobal,
  data,
  isLoading,
  queryClient,
  queryKey,
}: SettingsBlockProps & {
  data: ConfigResp | undefined;
  isLoading: boolean;
  queryClient: ReturnType<typeof useQueryClient>;
  queryKey: (string | Scope)[];
}) {
  const [provider, setProvider] = useState<Provider>(data?.data.provider ?? 'openai');
  const [model, setModel] = useState<string>(data?.data.model ?? 'gpt-4o-mini');
  const [apiKey, setApiKey] = useState('');
  const [showKey, setShowKey] = useState(false);
  const [useGlobal, setUseGlobal] = useState(data?.data.useGlobal ?? false);
  const [aiEnabled, setAiEnabled] = useState(data?.data.aiEnabled ?? false);
  const [manualEntry, setManualEntry] = useState(data?.data.manualEntry ?? false);
  const [testStatus, setTestStatus] = useState<null | { ok: true } | { ok: false; reason: string }>(
    null,
  );

  const save = useMutation({
    mutationFn: (clearApiKey?: boolean) =>
      apiFetch('/api/v1/admin/ocr-settings', {
        method: 'PUT',
        body: {
          scope,
          provider,
          model,
          apiKey: apiKey.length > 0 ? apiKey : undefined,
          clearApiKey: Boolean(clearApiKey),
          useGlobal: scope === 'global' ? false : useGlobal,
          aiEnabled: scope === 'global' ? false : aiEnabled,
          manualEntry: scope === 'global' ? false : manualEntry,
        },
      }),
    onSuccess: () => {
      setApiKey('');
      queryClient.invalidateQueries({ queryKey });
    },
  });

  const test = useMutation({
    mutationFn: () =>
      apiFetch<{ ok: boolean; reason?: string }>(`/api/v1/admin/ocr-settings/test`, {
        method: 'POST',
        body: { provider, model, apiKey },
      }),
    onSuccess: (res) =>
      setTestStatus(res.ok ? { ok: true } : { ok: false, reason: res.reason ?? 'Unknown' }),
    onError: (err: unknown) =>
      setTestStatus({
        ok: false,
        reason: err instanceof Error ? err.message : 'Network error',
      }),
  });

  const models = data?.models[provider] ?? [];
  const hasKey = data?.data.hasApiKey ?? false;

  if (isLoading) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{title}</CardTitle>
        </CardHeader>
        <CardContent className="flex items-center gap-2 text-sm text-muted-foreground">
          <Loader2 className="h-4 w-4 animate-spin" aria-hidden /> Loading…
        </CardContent>
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        <p className="text-sm text-muted-foreground">{description}</p>
      </CardHeader>
      <CardContent className="space-y-4">
        {showUseGlobal ? (
          <div className="flex items-start gap-2 rounded-lg border border-border bg-muted/30 p-3">
            <Checkbox
              id={`useGlobal-${scope}`}
              checked={useGlobal}
              onCheckedChange={(v) => setUseGlobal(v === true)}
            />
            <div className="space-y-0.5">
              <Label htmlFor={`useGlobal-${scope}`} className="text-sm font-medium">
                Use the global API key for this port
              </Label>
              <p className="text-xs text-muted-foreground">
                When enabled, this port falls back to the system-wide OCR settings. Per-port
                provider/model/key are ignored.
              </p>
            </div>
          </div>
        ) : null}

        {scope === 'port' ? (
          <div className="flex items-start gap-2 rounded-lg border border-border bg-muted/30 p-3">
            <Checkbox
              id={`aiEnabled-${scope}`}
              checked={aiEnabled}
              onCheckedChange={(v) => setAiEnabled(v === true)}
            />
            <div className="space-y-0.5">
              <Label htmlFor={`aiEnabled-${scope}`} className="text-sm font-medium">
                Enable AI receipt parsing for this port
              </Label>
              <p className="text-xs text-muted-foreground">
                Off by default. Receipts are read on-device using Tesseract.js - accurate enough for
                most receipts and incurs no AI cost. Turning this on lets the configured provider
                re-parse receipts server-side for higher accuracy on hard-to-read images.
              </p>
            </div>
          </div>
        ) : null}

        {scope === 'port' ? (
          <div className="flex items-start gap-2 rounded-lg border border-border bg-muted/30 p-3">
            <Checkbox
              id={`manualEntry-${scope}`}
              checked={manualEntry}
              onCheckedChange={(v) => setManualEntry(v === true)}
            />
            <div className="space-y-0.5">
              <Label htmlFor={`manualEntry-${scope}`} className="text-sm font-medium">
                Manual entry only (skip receipt scanning)
              </Label>
              <p className="text-xs text-muted-foreground">
                When on, staff just attach a receipt photo and type the details by hand - no
                on-device or AI parsing runs. Takes precedence over AI parsing above.
              </p>
            </div>
          </div>
        ) : null}

        <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
          <div className="space-y-1.5">
            <Label htmlFor={`provider-${scope}`}>Provider</Label>
            <Select
              value={provider}
              onValueChange={(v) => {
                const p = v as Provider;
                setProvider(p);
                setModel(data?.models[p][0] ?? '');
                setTestStatus(null);
              }}
            >
              <SelectTrigger id={`provider-${scope}`}>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="openai">OpenAI</SelectItem>
                <SelectItem value="claude">Claude (Anthropic)</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div className="space-y-1.5">
            <Label htmlFor={`model-${scope}`}>Model</Label>
            <Select value={model} onValueChange={setModel}>
              <SelectTrigger id={`model-${scope}`}>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {models.map((m) => (
                  <SelectItem key={m} value={m}>
                    {m}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        <div className="space-y-1.5">
          <Label htmlFor={`apiKey-${scope}`}>API key</Label>
          <div className="flex gap-2">
            <Input
              id={`apiKey-${scope}`}
              type={showKey ? 'text' : 'password'}
              autoComplete="off"
              placeholder={hasKey ? '•••••• (saved - leave blank to keep)' : 'sk-…'}
              value={apiKey}
              onChange={(e) => {
                setApiKey(e.target.value);
                setTestStatus(null);
              }}
            />
            <Button
              type="button"
              variant="outline"
              size="icon"
              onClick={() => setShowKey((v) => !v)}
              aria-label={showKey ? 'Hide key' : 'Show key'}
            >
              {showKey ? (
                <EyeOff className="h-4 w-4" aria-hidden />
              ) : (
                <Eye className="h-4 w-4" aria-hidden />
              )}
            </Button>
          </div>
          <p className="text-xs text-muted-foreground">
            Stored encrypted at rest. Never re-displayed after saving.
          </p>
        </div>

        <div className="flex flex-wrap items-center gap-2">
          <Button
            onClick={() => save.mutate(false)}
            disabled={save.isPending}
            data-testid={`save-${scope}`}
          >
            {save.isPending ? (
              <Loader2 className="mr-1.5 h-3 w-3 animate-spin" aria-hidden />
            ) : null}
            Save settings
          </Button>
          <Button
            type="button"
            variant="outline"
            onClick={() => test.mutate()}
            disabled={test.isPending || apiKey.length === 0}
          >
            {test.isPending ? (
              <Loader2 className="mr-1.5 h-3 w-3 animate-spin" aria-hidden />
            ) : null}
            Test connection
          </Button>
          {hasKey ? (
            <Button
              type="button"
              variant="ghost"
              onClick={() => save.mutate(true)}
              disabled={save.isPending}
              className="text-destructive"
            >
              Clear stored key
            </Button>
          ) : null}

          {testStatus?.ok ? (
            <span className="inline-flex items-center gap-1 text-sm text-green-700">
              <CheckCircle2 className="h-4 w-4" aria-hidden />
              Connection OK
            </span>
          ) : null}
          {testStatus && !testStatus.ok ? (
            <span className="inline-flex items-center gap-1 text-sm text-destructive">
              <XCircle className="h-4 w-4" aria-hidden />
              {testStatus.reason}
            </span>
          ) : null}
        </div>
      </CardContent>
    </Card>
  );
}

export function OcrSettingsForm({ embedded = false }: { embedded?: boolean } = {}) {
  const { isSuperAdmin } = usePermissions();

  return (
    <div className="space-y-6">
      {embedded ? null : (
        <PageHeader
          title="Receipt OCR"
          eyebrow="Admin"
          description="Receipts are scanned on-device by default. Optionally configure an AI provider for higher-accuracy parsing on tricky receipts."
          variant="gradient"
        />
      )}

      <SettingsBlock
        scope="port"
        title="This port"
        description="Optional AI provider for staff at this port. Tesseract.js handles all scans on-device until AI is enabled."
        showUseGlobal
      />

      <AiBudgetCard />

      {isSuperAdmin ? (
        <SettingsBlock
          scope="global"
          title="Global default"
          description="Used by any port that opted into the global key. Super-admin only."
        />
      ) : null}
    </div>
  );
}
