"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { Button, Card, Toggle } from "@/shared/components";
import { useNotificationStore } from "@/store/notificationStore";
import { useTranslations } from "next-intl";

type ModelLockoutSettings = {
  enabled: boolean;
  errorCodes: number[];
  baseCooldownMs: number;
  maxCooldownMs: number;
  maxBackoffSteps: number;
  useExponentialBackoff: boolean;
};

const DEFAULTS: ModelLockoutSettings = {
  enabled: false,
  errorCodes: [403, 404, 429, 502, 503, 504],
  baseCooldownMs: 120_000,
  maxCooldownMs: 1_800_000,
  maxBackoffSteps: 10,
  useExponentialBackoff: true,
};



function NumberField({
  label,
  value,
  suffix,
  min = 0,
  max,
  hint,
  onChange,
}: {
  label: string;
  value: number;
  suffix?: string;
  min?: number;
  max?: number;
  hint?: string;
  onChange: (value: number) => void;
}) {
  return (
    <label className="flex flex-col gap-1">
      <span className="flex items-center justify-between text-xs text-text-muted">
        <span>{label}</span>
        {hint ? <span className="text-text-soft">{hint}</span> : null}
      </span>
      <div className="flex items-center gap-2">
        <input
          type="number"
          min={min}
          max={max}
          value={value}
          onChange={(event) => {
            if (event.target.value === "") return;
            const nextValue = Number(event.target.value);
            if (Number.isFinite(nextValue)) {
              onChange(nextValue);
            }
          }}
          className="w-full rounded-lg border border-border bg-bg-subtle px-3 py-2 text-sm"
        />
        {suffix ? <span className="text-xs text-text-muted">{suffix}</span> : null}
      </div>
    </label>
  );
}

export default function ModelLockoutCard() {
  const t = useTranslations("settings");
  const tc = useTranslations("common");
  const notify = useNotificationStore();

  const [data, setData] = useState<ModelLockoutSettings>(DEFAULTS);
  const [draft, setDraft] = useState<ModelLockoutSettings>(DEFAULTS);
  const [errorCodesInput, setErrorCodesInput] = useState("");
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    let mounted = true;

    const load = async () => {
      try {
        const res = await fetch("/api/settings", { cache: "no-store" });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const json = await res.json();
        if (!mounted) return;

        const raw = (json as Record<string, unknown>).modelLockout as
          | Record<string, unknown>
          | undefined;

        const parsed: ModelLockoutSettings = {
          enabled:
            typeof raw?.enabled === "boolean" ? raw.enabled : DEFAULTS.enabled,
          errorCodes: Array.isArray(raw?.errorCodes)
            ? [...(raw.errorCodes as number[])].sort((a, b) => a - b)
            : [...DEFAULTS.errorCodes].sort((a, b) => a - b),
          baseCooldownMs:
            typeof raw?.baseCooldownMs === "number"
              ? raw.baseCooldownMs
              : DEFAULTS.baseCooldownMs,
          maxCooldownMs:
            typeof raw?.maxCooldownMs === "number"
              ? raw.maxCooldownMs
              : DEFAULTS.maxCooldownMs,
          maxBackoffSteps:
            typeof raw?.maxBackoffSteps === "number"
              ? raw.maxBackoffSteps
              : DEFAULTS.maxBackoffSteps,
          useExponentialBackoff:
            typeof raw?.useExponentialBackoff === "boolean"
              ? raw.useExponentialBackoff
              : DEFAULTS.useExponentialBackoff,
        };

        setData(parsed);
        setDraft(parsed);
        setErrorCodesInput("");
      } catch (error) {
        notify.error(
          error instanceof Error
            ? error.message
            : "Failed to load model lockout settings"
        );
      } finally {
        if (mounted) setLoading(false);
      }
    };

    void load();
    return () => {
      mounted = false;
    };
  }, []);

  const hasChanges =
    draft.enabled !== data.enabled ||
    JSON.stringify([...draft.errorCodes].sort((a, b) => a - b)) !==
      JSON.stringify([...data.errorCodes].sort((a, b) => a - b)) ||
    draft.baseCooldownMs !== data.baseCooldownMs ||
    draft.maxCooldownMs !== data.maxCooldownMs ||
    draft.useExponentialBackoff !== data.useExponentialBackoff ||
    draft.maxBackoffSteps !== data.maxBackoffSteps;

  function validateDraft(d: ModelLockoutSettings): string | null {
    if (d.baseCooldownMs < 5000 || d.baseCooldownMs > 600000)
      return `Base Cooldown must be between 5,000ms and 600,000ms`;
    if (d.maxCooldownMs < 5000 || d.maxCooldownMs > 3600000)
      return `Max Cooldown must be between 5,000ms and 3,600,000ms`;
    if (d.maxCooldownMs < d.baseCooldownMs)
      return `Max Cooldown must be ≥ Base Cooldown`;
    if (d.maxBackoffSteps < 0 || d.maxBackoffSteps > 20)
      return `Max Backoff Steps must be between 0 and 20`;
    return null;
  }

  const handleSave = async () => {
    const validationError = validateDraft(draft);
    if (validationError) {
      notify.error(validationError);
      return;
    }
    setSaving(true);
    const saveDraft = { ...draft, errorCodes: draft.errorCodes };
    try {
      const res = await fetch("/api/settings", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ modelLockout: saveDraft }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => null);
        const issues = err?.error?.issues ?? err?.error?.details;
        if (Array.isArray(issues) && issues.length > 0) {
          const fieldLabels: Record<string, string> = {
            "modelLockout.baseCooldownMs": "Base Cooldown",
            "modelLockout.maxCooldownMs": "Max Cooldown",
            "modelLockout.maxBackoffSteps": "Max Backoff Steps",
            "modelLockout.errorCodes": "Error Codes",
          };
          const msg = issues
            .map(
              (d: { path?: (string | number)[]; message?: string }) =>
                `${fieldLabels[String(d.path?.[0])] || String(d.path?.[0] || "")}: ${d.message}`
            )
            .filter(Boolean)
            .join("\n");
          if (msg) throw new Error(msg);
        }
        throw new Error(
          err?.error?.message || `HTTP ${res.status}`
        );
      }
      const json = await res.json();
      const raw = (json as Record<string, unknown>).modelLockout as
        | Record<string, unknown>
        | undefined;
      if (raw) {
        setData({
          enabled:
            typeof raw.enabled === "boolean" ? raw.enabled : saveDraft.enabled,
          errorCodes: Array.isArray(raw.errorCodes)
            ? [...(raw.errorCodes as number[])].sort((a, b) => a - b)
            : [...saveDraft.errorCodes].sort((a, b) => a - b),
          baseCooldownMs:
            typeof raw.baseCooldownMs === "number"
              ? raw.baseCooldownMs
              : saveDraft.baseCooldownMs,
          maxCooldownMs:
            typeof raw.maxCooldownMs === "number"
              ? raw.maxCooldownMs
              : saveDraft.maxCooldownMs,
          maxBackoffSteps:
            typeof raw.maxBackoffSteps === "number"
              ? raw.maxBackoffSteps
              : saveDraft.maxBackoffSteps,
          useExponentialBackoff:
            typeof raw.useExponentialBackoff === "boolean"
              ? raw.useExponentialBackoff
              : saveDraft.useExponentialBackoff,
        });
      } else {
        setData(saveDraft);
      }
      setErrorCodesInput("");
      notify.success(t("savedSuccessfully") || "Settings saved successfully");
    } catch (error) {
      notify.error(
        error instanceof Error
          ? error.message
          : "Failed to save model lockout settings"
      );
    } finally {
      setSaving(false);
    }
  };

  const handleReset = () => {
    setDraft(data);
    setErrorCodesInput("");
  };

  const commitErrorCodes = (inputOverride?: string) => {
    const raw = inputOverride ?? errorCodesInput;
    const code = Number(raw);
    if (!Number.isFinite(code) || code < 100 || code > 599) return;
    if (draft.errorCodes.includes(code)) {
      setErrorCodesInput("");
      return;
    }
    setDraft((prev) => ({ ...prev, errorCodes: [...prev.errorCodes, code].sort((a, b) => a - b) }));
    setErrorCodesInput("");
  };

  const removeErrorCode = (code: number) => {
    setDraft((prev) => ({ ...prev, errorCodes: prev.errorCodes.filter((c) => c !== code) }));
  };

  const handleResetDefaults = () => {
    setDraft({
      ...DEFAULTS,
      errorCodes: [...DEFAULTS.errorCodes].sort((a, b) => a - b),
    });
    setErrorCodesInput("");
  };

  const fmt = (ms: number) => {
    if (ms >= 60_000) return `${ms / 1000 / 60}m`;
    if (ms >= 1_000) return `${ms / 1000}s`;
    return `${ms}ms`;
  };

  const notifyRef = useRef<HTMLAudioElement | null>(null);
  const playNotify = useCallback(() => {
    try {
      if (notifyRef.current) {
        notifyRef.current.pause();
        notifyRef.current.currentTime = 0;
      } else {
        notifyRef.current = new Audio("/audio/ui-notify.mp3");
        notifyRef.current.volume = 0.3;
      }
      void notifyRef.current.play();
    } catch { /* audio not available */ }
  }, []);

  if (loading) {
    return (
      <Card className="p-6">
        <div className="flex items-center gap-2 text-sm text-text-muted">
          <span className="material-symbols-outlined animate-spin">
            progress_activity
          </span>
          Loading model lockout settings...
        </div>
      </Card>
    );
  }

  return (
    <Card className="p-6">
      <div className="mb-4 flex items-start justify-between gap-4">
        <div className="space-y-2">
          <div className="flex items-center gap-2">
            <span className="material-symbols-outlined text-xl text-primary">
              gpp_maybe
            </span>
            <h2 className="text-lg font-bold">
              {t("modelLockout") || "Model Lockout"}
            </h2>
          </div>
          <p className="text-sm text-text-muted">
            {t("modelLockoutPageDescription")}
          </p>
        </div>
        {hasChanges ? (
          <div className="flex flex-wrap gap-2">
            <Button size="sm" variant="secondary" onClick={handleReset}>
              {tc("cancel")}
            </Button>
            <Button
              size="sm"
              variant="primary"
              icon="save"
              onClick={handleSave}
              disabled={saving}
            >
              {saving ? tc("saving") || "Saving..." : tc("save")}
            </Button>
          </div>
        ) : (
          <Button
            size="sm"
            variant="secondary"
            onClick={handleResetDefaults}
          >
            Reset defaults
          </Button>
        )}
      </div>

      <div className="space-y-5">
        {/* Master toggle */}
        <div className="rounded-lg border border-border bg-bg-subtle px-4 py-3">
          <Toggle
            checked={draft.enabled}
            onChange={(checked) => {
              setDraft((prev) => ({ ...prev, enabled: checked }));
              playNotify();
            }}
            label={t("modelLockoutEnabled")}
            description={t("modelLockoutEnabledDescription")}
          />
        </div>

        {/* Error codes — tag input */}
        <div className="rounded-lg border border-border bg-bg-subtle p-4">
          <label className="flex flex-col gap-1.5">
            <span className="text-sm font-medium text-text-main">
              {t("modelLockoutErrorCodes")}
            </span>
            <span className="text-xs text-text-muted">
              {t("modelLockoutErrorCodesDescription")}
            </span>
          </label>

          {/* Chips row */}
          {draft.errorCodes.length > 0 && (
            <div className="mt-3 flex flex-wrap items-center gap-1.5">
              {draft.errorCodes.map((code) => (
                <span
                  key={code}
                  className="inline-flex items-center gap-1 rounded-md bg-primary/10 text-primary border border-primary/20 px-2 py-1 text-sm font-medium"
                >
                  {code}
                  <button
                    type="button"
                    onClick={() => removeErrorCode(code)}
                    className="inline-flex size-4 items-center justify-center rounded-sm hover:bg-primary/20 transition-colors"
                    aria-label={`Remove ${code}`}
                  >
                    <span className="material-symbols-outlined text-sm leading-none">close</span>
                  </button>
                </span>
              ))}
            </div>
          )}

          {/* Input row */}
          <div className="mt-3 flex items-center gap-2">
            <input
              type="text"
              inputMode="numeric"
              value={errorCodesInput}
              onChange={(e) => {
                const raw = e.target.value.replace(/[^0-9]/g, "");
                if (raw.length <= 3) setErrorCodesInput(raw);
              }}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault();
                  commitErrorCodes();
                }
              }}
              placeholder="Add error code..."
              className="w-32 rounded-lg border border-border bg-bg px-3 py-2 text-sm outline-none focus:border-primary transition-colors placeholder:text-text-muted/50"
            />
            <button
              type="button"
              onClick={() => commitErrorCodes()}
              disabled={!errorCodesInput.trim()}
              className="rounded-lg border border-border bg-bg px-3 py-2 text-sm text-text-muted hover:text-text-main hover:border-primary/40 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
            >
              Add
            </button>
          </div>

          {/* Suggested common codes — chips as clickable suggestions */}
          {draft.errorCodes.length === 0 && errorCodesInput === "" && (
            <div className="mt-3 flex flex-wrap items-center gap-1.5">
              <span className="text-xs text-text-muted mr-1">Suggestions:</span>
              {[403, 404, 429, 502, 503, 504].map((code) => (
                <button
                  key={code}
                  type="button"
                  onClick={() => commitErrorCodes(String(code))}
                  className="inline-flex items-center px-2 py-0.5 rounded-full bg-surface text-xs text-text-muted border border-border/40 hover:border-primary/40 hover:text-primary transition-colors"
                >
                  +{code}
                </button>
              ))}
            </div>
          )}
        </div>

        {/* Cooldowns - grid */}
        <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
          <div className="rounded-lg border border-border bg-bg-subtle p-4">
            <NumberField
              label={t("modelLockoutBaseCooldown")}
              value={draft.baseCooldownMs}
              min={5000}
              max={600000}
              suffix="ms"
              hint="5,000ms — 600,000ms"
              onChange={(baseCooldownMs) =>
                setDraft((prev) => ({ ...prev, baseCooldownMs }))
              }
            />
            <p className="mt-1.5 text-xs text-text-muted">
              {t("modelLockoutBaseCooldownDescription")}
            </p>
          </div>

          <div className="rounded-lg border border-border bg-bg-subtle p-4">
            <NumberField
              label={t("modelLockoutMaxCooldown")}
              value={draft.maxCooldownMs}
              min={draft.baseCooldownMs}
              max={3600000}
              suffix="ms"
              hint="≥ Base Cooldown — 3,600,000ms"
              onChange={(maxCooldownMs) =>
                setDraft((prev) => ({ ...prev, maxCooldownMs }))
              }
            />
            <p className="mt-1.5 text-xs text-text-muted">
              {t("modelLockoutMaxCooldownDescription")}
            </p>
          </div>
        </div>

        {/* Exponential backoff */}
        <div className="rounded-lg border border-border bg-bg-subtle px-4 py-3">
          <Toggle
            checked={draft.useExponentialBackoff}
            onChange={(checked) => {
              setDraft((prev) => ({
                ...prev,
                useExponentialBackoff: checked,
              }));
              playNotify();
            }}
            label={t("modelLockoutExponentialBackoff")}
            description={t("modelLockoutExponentialBackoffDescription")}
          />
        </div>

        {/* Max backoff steps */}
        <div className="rounded-lg border border-border bg-bg-subtle p-4">
          <NumberField
            label={t("modelLockoutMaxBackoffSteps")}
            value={draft.maxBackoffSteps}
            min={0}
            onChange={(maxBackoffSteps) =>
              setDraft((prev) => ({ ...prev, maxBackoffSteps }))
            }
          />
          <p className="mt-1.5 text-xs text-text-muted">
            {t("modelLockoutMaxBackoffStepsDescription")}
          </p>
        </div>
      </div>
    </Card>
  );
}
