import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import {
  Activity,
  CheckCircle2,
  Eye,
  EyeOff,
  Image as ImageIcon,
  Loader2,
  Save,
  Settings2,
  Volume2,
  Wand2,
  XCircle,
} from "lucide-react";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Skeleton } from "@/components/ui/skeleton";
import {
  aiSettingsService,
  type AISettingsPatchPayload,
  type AISettingsState,
  type CapabilityKey,
  type CapabilityState,
  type ProviderTestResult,
} from "@/services/aiSettings.service";

/**
 * Admin UI for AI provider selection and API-key management.
 *
 * - Dropdowns set the active provider per capability (text / image / audio /
 *   video). Selecting "auto" tells the backend to try paid providers first
 *   and silently fall back to free providers on quota / billing errors.
 * - API-key inputs are write-only — the backend never returns a key value;
 *   we only render a "saved" badge based on `keys_set[<name>]`.
 * - Changes persist to `ir.config_parameter` and take effect on the very
 *   next request (no caching), so admins can flip OpenAI -> Mock without
 *   restarting Odoo.
 *
 * Mounted as the fourth tab on `/admin/ai/prompts` so the user keeps a
 * single "AI" surface in the admin nav.
 */

const CAPABILITY_META: Array<{
  key: CapabilityKey;
  icon: React.ComponentType<{ className?: string }>;
  i18nKey: string;
  defaultLabel: string;
}> = [
  { key: "text",  icon: Wand2,     i18nKey: "aiProviders.cap.text",  defaultLabel: "Text generation" },
  { key: "image", icon: ImageIcon, i18nKey: "aiProviders.cap.image", defaultLabel: "Image generation" },
  { key: "audio", icon: Volume2,   i18nKey: "aiProviders.cap.audio", defaultLabel: "Audio (TTS)" },
  { key: "video", icon: Activity,  i18nKey: "aiProviders.cap.video", defaultLabel: "Video composition" },
];

interface KeyFieldDef {
  shortName: string;
  i18nKey: string;
  defaultLabel: string;
  placeholder?: string;
  hint?: string;
  hintI18nKey?: string;
  group: "openai" | "aws" | "elevenlabs" | "other" | "paymob";
}

const KEY_FIELDS: KeyFieldDef[] = [
  // OpenAI
  {
    shortName: "openai_api_key",
    i18nKey: "aiProviders.keys.openai",
    defaultLabel: "OpenAI API key",
    placeholder: "sk-…",
    hintI18nKey: "aiProviders.keys.openai_hint",
    hint: "Used for GPT-4o, embeddings, and DALL-E 3.",
    group: "openai",
  },
  // AWS
  {
    shortName: "aws_access_key",
    i18nKey: "aiProviders.keys.aws_access",
    defaultLabel: "AWS Access Key ID",
    placeholder: "AKIA…",
    group: "aws",
  },
  {
    shortName: "aws_secret_key",
    i18nKey: "aiProviders.keys.aws_secret",
    defaultLabel: "AWS Secret Access Key",
    placeholder: "wJalr…",
    group: "aws",
  },
  // ElevenLabs
  {
    shortName: "elevenlabs_api_key",
    i18nKey: "aiProviders.keys.elevenlabs",
    defaultLabel: "ElevenLabs API key",
    placeholder: "el_…",
    group: "elevenlabs",
  },
  // GPTZero
  {
    shortName: "gptzero_api_key",
    i18nKey: "aiProviders.keys.gptzero",
    defaultLabel: "GPTZero API key",
    group: "other",
  },
  // Paymob (payments)
  {
    shortName: "paymob_api_key",
    i18nKey: "aiProviders.keys.paymob_api",
    defaultLabel: "Paymob API key",
    group: "paymob",
  },
  {
    shortName: "paymob_integration_id",
    i18nKey: "aiProviders.keys.paymob_integration",
    defaultLabel: "Paymob integration ID",
    group: "paymob",
  },
  {
    shortName: "paymob_iframe_id",
    i18nKey: "aiProviders.keys.paymob_iframe",
    defaultLabel: "Paymob iframe ID",
    group: "paymob",
  },
  {
    shortName: "paymob_hmac_secret",
    i18nKey: "aiProviders.keys.paymob_hmac",
    defaultLabel: "Paymob HMAC secret",
    group: "paymob",
  },
];

const KEY_GROUPS: Array<{
  group: KeyFieldDef["group"];
  i18nKey: string;
  defaultLabel: string;
}> = [
  { group: "openai",     i18nKey: "aiProviders.group.openai",     defaultLabel: "OpenAI" },
  { group: "aws",        i18nKey: "aiProviders.group.aws",        defaultLabel: "AWS Polly" },
  { group: "elevenlabs", i18nKey: "aiProviders.group.elevenlabs", defaultLabel: "ElevenLabs" },
  { group: "other",      i18nKey: "aiProviders.group.other",      defaultLabel: "Other AI services" },
  { group: "paymob",     i18nKey: "aiProviders.group.paymob",     defaultLabel: "Paymob (payments)" },
];

const KIND_BADGE: Record<string, { className: string; labelKey: string; defaultLabel: string }> = {
  paid: { className: "bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-200",
          labelKey: "aiProviders.kind.paid", defaultLabel: "Paid" },
  free: { className: "bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-200",
          labelKey: "aiProviders.kind.free", defaultLabel: "Free" },
  auto: { className: "bg-blue-100 text-blue-800 dark:bg-blue-950 dark:text-blue-200",
          labelKey: "aiProviders.kind.auto", defaultLabel: "Auto" },
};

function CapabilityCard({
  capKey,
  state,
  onChange,
  onTest,
  testing,
  testResult,
}: {
  capKey: CapabilityKey;
  state: CapabilityState;
  onChange: (newValue: string) => void;
  onTest: () => void;
  testing: boolean;
  testResult: ProviderTestResult | null;
}) {
  const { t } = useTranslation();
  const meta = CAPABILITY_META.find((m) => m.key === capKey)!;
  const Icon = meta.icon;
  const activeOption = state.options.find((o) => o.value === state.active);

  return (
    <Card>
      <CardHeader>
        <div className="flex items-center justify-between gap-2">
          <CardTitle className="flex items-center gap-2 text-base">
            <Icon className="h-4 w-4" />
            {t(meta.i18nKey, meta.defaultLabel)}
          </CardTitle>
          {activeOption ? (
            <Badge
              variant="outline"
              className={KIND_BADGE[activeOption.kind]?.className}
            >
              {t(
                KIND_BADGE[activeOption.kind]?.labelKey ?? "aiProviders.kind.auto",
                KIND_BADGE[activeOption.kind]?.defaultLabel ?? activeOption.kind,
              )}
            </Badge>
          ) : null}
        </div>
        <CardDescription>
          {t(`${meta.i18nKey}_hint`, "Active provider for this capability.")}
        </CardDescription>
      </CardHeader>
      <CardContent className="space-y-3">
        <div className="space-y-1">
          <Label htmlFor={`provider-${capKey}`}>
            {t("aiProviders.activeProvider", "Active provider")}
          </Label>
          <Select value={state.active} onValueChange={onChange}>
            <SelectTrigger id={`provider-${capKey}`}>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {state.options.map((opt) => (
                <SelectItem key={opt.value} value={opt.value}>
                  <span className="flex items-center gap-2">
                    {opt.label}
                    <Badge
                      variant="outline"
                      className={`text-xs ${KIND_BADGE[opt.kind]?.className ?? ""}`}
                    >
                      {t(
                        KIND_BADGE[opt.kind]?.labelKey ?? "aiProviders.kind.auto",
                        KIND_BADGE[opt.kind]?.defaultLabel ?? opt.kind,
                      )}
                    </Badge>
                  </span>
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        {state.paid_with_credentials.length === 0 && capKey !== "video" ? (
          <p className="text-muted-foreground text-xs">
            {t(
              "aiProviders.noPaidKeys",
              "No paid API keys configured for this capability — free fallback will be used.",
            )}
          </p>
        ) : (
          <p className="text-muted-foreground text-xs">
            {t("aiProviders.paidConfigured", "Configured paid providers:")}{" "}
            {state.paid_with_credentials.join(", ") || "—"}
          </p>
        )}

        <div className="flex items-center gap-2">
          <Button
            type="button"
            variant="secondary"
            size="sm"
            onClick={onTest}
            disabled={testing}
          >
            {testing ? (
              <Loader2 className="me-1 h-3 w-3 animate-spin" />
            ) : null}
            {t("aiProviders.testButton", "Test fallback chain")}
          </Button>
          {testResult ? (
            <span className="text-muted-foreground text-xs">
              {testResult.chain
                .map((c) => `${c.provider}${c.ok ? " ✓" : " ✗"}`)
                .join(" → ")}
            </span>
          ) : null}
        </div>
      </CardContent>
    </Card>
  );
}

function SecretField({
  field,
  isSet,
  value,
  onChange,
  onClear,
}: {
  field: KeyFieldDef;
  isSet: boolean;
  value: string | undefined;
  onChange: (v: string) => void;
  onClear: () => void;
}) {
  const { t } = useTranslation();
  const [revealed, setRevealed] = useState(false);
  const dirty = value !== undefined;
  return (
    <div className="space-y-1">
      <div className="flex items-center justify-between gap-2">
        <Label htmlFor={`key-${field.shortName}`} className="text-sm">
          {t(field.i18nKey, field.defaultLabel)}
        </Label>
        <div className="flex items-center gap-2">
          {isSet && !dirty ? (
            <Badge
              variant="outline"
              className="bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-200"
            >
              <CheckCircle2 className="me-1 h-3 w-3" />
              {t("aiProviders.keys.saved", "Saved")}
            </Badge>
          ) : null}
          {dirty ? (
            <Badge
              variant="outline"
              className="bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-200"
            >
              {t("aiProviders.keys.unsaved", "Unsaved")}
            </Badge>
          ) : null}
        </div>
      </div>
      <div className="flex gap-2">
        <div className="relative flex-1">
          <Input
            id={`key-${field.shortName}`}
            type={revealed ? "text" : "password"}
            placeholder={
              isSet
                ? t("aiProviders.keys.placeholderSaved", "•••••• (click to replace)")
                : (field.placeholder ?? "")
            }
            value={value ?? ""}
            onChange={(e) => onChange(e.target.value)}
            autoComplete="off"
            spellCheck={false}
          />
          <button
            type="button"
            onClick={() => setRevealed((v) => !v)}
            className="text-muted-foreground hover:text-foreground absolute end-2 top-1/2 -translate-y-1/2"
            tabIndex={-1}
            aria-label={revealed ? "Hide value" : "Show value"}
          >
            {revealed ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
          </button>
        </div>
        {isSet ? (
          <Button
            type="button"
            variant="ghost"
            size="sm"
            onClick={onClear}
          >
            {t("aiProviders.keys.clear", "Clear")}
          </Button>
        ) : null}
      </div>
      {field.hint ? (
        <p className="text-muted-foreground text-xs">
          {t(field.hintI18nKey ?? "", field.hint)}
        </p>
      ) : null}
    </div>
  );
}

function PlainField({
  shortName,
  label,
  value,
  onChange,
}: {
  shortName: string;
  label: string;
  value: string;
  onChange: (v: string) => void;
}) {
  return (
    <div className="space-y-1">
      <Label htmlFor={`plain-${shortName}`} className="text-sm">
        {label}
      </Label>
      <Input
        id={`plain-${shortName}`}
        value={value}
        onChange={(e) => onChange(e.target.value)}
      />
    </div>
  );
}

export default function AIProviderSettings() {
  const { t } = useTranslation();
  const [state, setState] = useState<AISettingsState | null>(null);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);

  // Pending diff applied on Save. Provider edits are confirmed
  // immediately so the UI reflects the active selection — but we still
  // batch them into one PATCH so we don't burn requests on every click.
  const [pendingProviders, setPendingProviders] = useState<
    Partial<Record<CapabilityKey, string>>
  >({});
  const [pendingKeys, setPendingKeys] = useState<Record<string, string>>({});
  const [pendingPlain, setPendingPlain] = useState<Record<string, string>>({});

  const [testing, setTesting] = useState<CapabilityKey | null>(null);
  const [testResults, setTestResults] = useState<
    Partial<Record<CapabilityKey, ProviderTestResult>>
  >({});

  useEffect(() => {
    void load();
  }, []);

  async function load() {
    setLoading(true);
    try {
      const data = await aiSettingsService.get();
      setState(data);
      setPendingProviders({});
      setPendingKeys({});
      setPendingPlain({});
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(t("aiProviders.toast.loadFailed", "Could not load AI settings"), {
        description: msg,
      });
    } finally {
      setLoading(false);
    }
  }

  const dirty = useMemo(
    () =>
      Object.keys(pendingProviders).length > 0 ||
      Object.keys(pendingKeys).length > 0 ||
      Object.keys(pendingPlain).length > 0,
    [pendingProviders, pendingKeys, pendingPlain],
  );

  async function handleSave() {
    if (!state || !dirty) return;
    setSaving(true);
    try {
      const payload: AISettingsPatchPayload = {};
      if (Object.keys(pendingProviders).length) payload.providers = pendingProviders;
      if (Object.keys(pendingKeys).length) payload.keys = pendingKeys;
      if (Object.keys(pendingPlain).length) payload.plain = pendingPlain;
      const updated = await aiSettingsService.update(payload);
      setState(updated);
      setPendingProviders({});
      setPendingKeys({});
      setPendingPlain({});
      toast.success(
        t("aiProviders.toast.saved", "AI provider settings saved"),
        {
          description: t(
            "aiProviders.toast.savedDescription",
            "Active providers updated. Changes apply to the next request.",
          ),
        },
      );
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(t("aiProviders.toast.saveFailed", "Could not save settings"), {
        description: msg,
      });
    } finally {
      setSaving(false);
    }
  }

  async function handleTest(cap: CapabilityKey) {
    setTesting(cap);
    try {
      const result = await aiSettingsService.test(cap);
      setTestResults((prev) => ({ ...prev, [cap]: result }));
      const allOk = result.chain.every((c) => c.ok);
      if (allOk) {
        toast.success(
          t("aiProviders.toast.testOk", "Provider chain ready") +
            ` · ${result.chain.map((c) => c.provider).join(" → ")}`,
        );
      } else {
        toast.warning(
          t("aiProviders.toast.testPartial", "Some providers missing credentials") +
            ` · ${result.chain
              .map((c) => `${c.provider}${c.ok ? "✓" : "✗"}`)
              .join(" → ")}`,
        );
      }
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(t("aiProviders.toast.testFailed", "Provider test failed"), {
        description: msg,
      });
    } finally {
      setTesting(null);
    }
  }

  if (loading) {
    return (
      <div className="space-y-4">
        <Skeleton className="h-32 w-full" />
        <Skeleton className="h-64 w-full" />
      </div>
    );
  }

  if (!state) {
    return (
      <div className="text-muted-foreground py-12 text-center text-sm">
        {t("aiProviders.empty", "Settings could not be loaded.")}
      </div>
    );
  }

  const effectiveProviders: Record<CapabilityKey, CapabilityState> = {
    text: { ...state.providers.text, active: pendingProviders.text ?? state.providers.text.active },
    image: { ...state.providers.image, active: pendingProviders.image ?? state.providers.image.active },
    audio: { ...state.providers.audio, active: pendingProviders.audio ?? state.providers.audio.active },
    video: { ...state.providers.video, active: pendingProviders.video ?? state.providers.video.active },
  };

  return (
    <div className="space-y-6">
      <Card>
        <CardHeader>
          <div className="flex flex-wrap items-center justify-between gap-3">
            <div>
              <CardTitle className="flex items-center gap-2 text-lg">
                <Settings2 className="h-5 w-5" />
                {t("aiProviders.title", "AI Providers & API Keys")}
              </CardTitle>
              <CardDescription>
                {t(
                  "aiProviders.subtitle",
                  "Pick the active provider per capability and store API keys. Changes take effect on the next request — no Odoo restart required.",
                )}
              </CardDescription>
            </div>
            <Button
              onClick={handleSave}
              disabled={!dirty || saving}
              className="shrink-0"
            >
              {saving ? (
                <Loader2 className="me-1 h-4 w-4 animate-spin" />
              ) : (
                <Save className="me-1 h-4 w-4" />
              )}
              {t("aiProviders.save", "Save settings")}
            </Button>
          </div>
        </CardHeader>
      </Card>

      <div className="grid gap-4 md:grid-cols-2">
        {CAPABILITY_META.map((meta) => (
          <CapabilityCard
            key={meta.key}
            capKey={meta.key}
            state={effectiveProviders[meta.key]}
            onChange={(newValue) =>
              setPendingProviders((prev) => ({ ...prev, [meta.key]: newValue }))
            }
            onTest={() => handleTest(meta.key)}
            testing={testing === meta.key}
            testResult={testResults[meta.key] ?? null}
          />
        ))}
      </div>

      <Card>
        <CardHeader>
          <CardTitle className="text-base">
            {t("aiProviders.keys.title", "API keys")}
          </CardTitle>
          <CardDescription>
            {t(
              "aiProviders.keys.subtitle",
              "Keys are write-only and stored encrypted at rest in ir.config_parameter. They are never returned to the browser.",
            )}
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-6">
          {KEY_GROUPS.map((group) => {
            const fields = KEY_FIELDS.filter((f) => f.group === group.group);
            if (!fields.length) return null;
            return (
              <div key={group.group} className="space-y-3">
                <h3 className="text-sm font-semibold">
                  {t(group.i18nKey, group.defaultLabel)}
                </h3>
                <div className="grid gap-4 md:grid-cols-2">
                  {fields.map((field) => (
                    <SecretField
                      key={field.shortName}
                      field={field}
                      isSet={Boolean(state.keys_set[field.shortName])}
                      value={pendingKeys[field.shortName]}
                      onChange={(v) =>
                        setPendingKeys((prev) => ({
                          ...prev,
                          [field.shortName]: v,
                        }))
                      }
                      onClear={() =>
                        setPendingKeys((prev) => ({
                          ...prev,
                          [field.shortName]: "",
                        }))
                      }
                    />
                  ))}
                </div>
              </div>
            );
          })}
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle className="text-base">
            {t("aiProviders.plain.title", "Model & runtime")}
          </CardTitle>
          <CardDescription>
            {t(
              "aiProviders.plain.subtitle",
              "Non-secret runtime parameters: default model, AWS region, request timeout.",
            )}
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-4 md:grid-cols-2">
          <PlainField
            shortName="openai_model"
            label={t("aiProviders.plain.openai_model", "OpenAI model")}
            value={pendingPlain.openai_model ?? state.plain.openai_model ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, openai_model: v }))
            }
          />
          <PlainField
            shortName="openai_fast_model"
            label={t("aiProviders.plain.openai_fast", "OpenAI fast model")}
            value={pendingPlain.openai_fast_model ?? state.plain.openai_fast_model ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, openai_fast_model: v }))
            }
          />
          <PlainField
            shortName="aws_region"
            label={t("aiProviders.plain.aws_region", "AWS region")}
            value={pendingPlain.aws_region ?? state.plain.aws_region ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, aws_region: v }))
            }
          />
          <PlainField
            shortName="elevenlabs_model"
            label={t("aiProviders.plain.elevenlabs_model", "ElevenLabs model")}
            value={pendingPlain.elevenlabs_model ?? state.plain.elevenlabs_model ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, elevenlabs_model: v }))
            }
          />
          <PlainField
            shortName="request_timeout"
            label={t("aiProviders.plain.timeout", "Request timeout (seconds)")}
            value={pendingPlain.request_timeout ?? state.plain.request_timeout ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, request_timeout: v }))
            }
          />
          <PlainField
            shortName="max_retries"
            label={t("aiProviders.plain.max_retries", "Max retries")}
            value={pendingPlain.max_retries ?? state.plain.max_retries ?? ""}
            onChange={(v) =>
              setPendingPlain((prev) => ({ ...prev, max_retries: v }))
            }
          />
        </CardContent>
      </Card>

      <p className="text-muted-foreground text-xs">
        {t(
          "aiProviders.footer",
          "Provider settings are read fresh from ir.config_parameter on every request — no caching, no restart required.",
        )}
      </p>
    </div>
  );
}
