import { type JSX, useState, useCallback } from "react";
import { Settings } from "lucide-react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
import { Button } from "../ui/button";
import { ProvidersPanel } from "./ProvidersPanel";
import { useProviders } from "../../lib/useProviders";
import { useStripConfig } from "../../lib/useStripConfig";
import { MAX_SLOW_RESPONSE_THRESHOLD_SECONDS } from "../../lib/runtimeConfig";

export function SettingsDialog(): JSX.Element {
  const [open, setOpen] = useState(false);
  const [activeTab, setActiveTab] = useState("providers");
  const { providers, isLoading, mutate } = useProviders();
  const [testResults, setTestResults] = useState<
    Record<string, import("./ProvidersPanel").TestResults>
  >({});
  const [testingProviders, setTestingProviders] = useState<Set<string>>(new Set());
  const [testingTimeLeft, setTestingTimeLeft] = useState<Record<string, number>>({});

  const handleTestResultsChange = useCallback(
    (providerId: string, results: import("./ProvidersPanel").TestResults) => {
      setTestResults((prev) => ({ ...prev, [providerId]: results }));
    },
    [],
  );

  const handleTestingProvidersChange = useCallback((providerId: string, isTesting: boolean) => {
    setTestingProviders((prev) => {
      const next = new Set(prev);
      if (isTesting) {
        next.add(providerId);
      } else {
        next.delete(providerId);
      }
      return next;
    });
  }, []);

  const handleTestingTimeLeftChange = useCallback(
    (providerId: string, seconds: number | undefined) => {
      setTestingTimeLeft((prev) => {
        if (seconds === undefined) {
          const next = { ...prev };
          delete next[providerId];
          return next;
        }
        return { ...prev, [providerId]: seconds };
      });
    },
    [],
  );

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button variant="ghost" size="icon" className="size-8">
          <Settings className="size-4" />
          <span className="sr-only">Settings</span>
        </Button>
      </DialogTrigger>
      <DialogContent className="max-w-2xl max-h-[80vh] overflow-hidden flex flex-col">
        <DialogHeader>
          <DialogTitle>Settings</DialogTitle>
        </DialogHeader>

        <Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1 overflow-hidden">
          <TabsList>
            <TabsTrigger value="providers">Providers</TabsTrigger>
            <TabsTrigger value="proxy">Proxy</TabsTrigger>
          </TabsList>

          <div className="mt-4 overflow-y-auto flex-1 pr-3">
            <TabsContent value="providers">
              <ProvidersPanel
                externalProviders={providers}
                isLoading={isLoading}
                externalTestResults={testResults}
                externalTestingProviders={testingProviders}
                externalTestingTimeLeft={testingTimeLeft}
                onProvidersMutate={() => {
                  return mutate();
                }}
                onTestResultsChange={handleTestResultsChange}
                onTestingProvidersChange={handleTestingProvidersChange}
                onTestingTimeLeftChange={handleTestingTimeLeftChange}
              />
            </TabsContent>
            <TabsContent value="proxy">
              <ProxySettingsTab />
            </TabsContent>
          </div>
        </Tabs>
      </DialogContent>
    </Dialog>
  );
}

function ProxySettingsTab(): JSX.Element {
  const {
    strip,
    slowResponseThresholdSeconds,
    isLoading,
    setStrip,
    setSlowResponseThresholdSeconds,
  } = useStripConfig();
  const [error, setError] = useState<string | null>(null);
  const [pending, setPending] = useState(false);

  const handleToggle = useCallback(
    async (next: boolean) => {
      setError(null);
      setPending(true);
      try {
        await setStrip(next);
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err));
      } finally {
        setPending(false);
      }
    },
    [setStrip],
  );

  const handleThresholdChange = useCallback(
    async (next: number) => {
      setError(null);
      setPending(true);
      try {
        await setSlowResponseThresholdSeconds(next);
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err));
      } finally {
        setPending(false);
      }
    },
    [setSlowResponseThresholdSeconds],
  );

  return (
    <div className="space-y-4">
      <div className="space-y-1">
        <h3 className="text-sm font-semibold">Claude Code billing header</h3>
        <p className="text-xs text-muted-foreground">
          When enabled, the proxy strips the synthetic <code>x-anthropic-billing-header</code> text
          block that Claude Code prepends to the system prompt before forwarding to upstream.
          Improves prefix-cache hit rates against third-party upstreams. The default at startup is
          controlled by the <code>LLM_INSPECTOR_STRIP_CLAUDE_CODE_BILLING_HEADER</code> environment
          variable; your choice is persisted to <code>config.json</code> and overrides the env var
          for subsequent requests.
        </p>
      </div>

      <label className="flex items-center gap-3">
        <input
          type="checkbox"
          role="switch"
          checked={strip}
          disabled={isLoading || pending}
          onChange={(e) => {
            void handleToggle(e.currentTarget.checked);
          }}
          className="size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
        />
        <span className="text-sm">
          {isLoading ? "Loading…" : strip ? "Stripping enabled" : "Stripping disabled"}
        </span>
      </label>

      <div className="space-y-1">
        <label htmlFor="slow-response-threshold" className="text-sm font-semibold">
          Slow response threshold
        </label>
        <p className="text-xs text-muted-foreground">
          Logs whose elapsed time exceeds this many seconds show a warning icon next to the
          duration. Set to <code>0</code> to disable the indicator.
        </p>
        <div className="flex items-center gap-2">
          <input
            id="slow-response-threshold"
            type="number"
            min={0}
            max={MAX_SLOW_RESPONSE_THRESHOLD_SECONDS}
            step={1}
            value={slowResponseThresholdSeconds}
            disabled={isLoading || pending}
            onChange={(e) => {
              const next = Number(e.currentTarget.value);
              if (!Number.isInteger(next)) return;
              if (next < 0 || next > MAX_SLOW_RESPONSE_THRESHOLD_SECONDS) return;
              void handleThresholdChange(next);
            }}
            className="h-8 w-24 rounded-md border border-input bg-transparent px-2 text-sm font-mono disabled:cursor-not-allowed disabled:opacity-50"
          />
          <span className="text-xs text-muted-foreground">seconds</span>
        </div>
      </div>

      {error !== null && <p className="text-xs text-destructive">Failed to save: {error}</p>}
    </div>
  );
}
