import { DEFAULT_OPENAI_MODEL } from "@nexus/shared";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import {
  INPUT_CLASS,
  LABEL_CLASS,
  PANEL_CLASS,
  PRIMARY_BUTTON_CLASS,
  SECONDARY_BUTTON_CLASS,
  RuntimeSecretCard,
  type Provider,
  type RuntimeSecretStatus,
  type SaveResult,
  type UrlParsedType,
} from "./shared.js";

type AiProviderPanelProps = {
  provider: Provider;
  endpoint: string;
  model: string;
  apiVersion: string;
  urlPasteValue: string;
  urlParseError: boolean;
  urlParsedType: UrlParsedType;
  runtimeSecret: RuntimeSecretStatus;
  testResult: SaveResult | null;
  isSaving: boolean;
  isTesting: boolean;
  saved: boolean;
  onProviderChange: (provider: Provider) => void;
  onEndpointChange: (value: string) => void;
  onModelChange: (value: string) => void;
  onApiVersionChange: (value: string) => void;
  onUrlPaste: (value: string) => void;
  onSave: () => void;
  onTest: () => void;
};

export function AiProviderPanel({
  provider,
  endpoint,
  model,
  apiVersion,
  urlPasteValue,
  urlParseError,
  urlParsedType,
  runtimeSecret,
  testResult,
  isSaving,
  isTesting,
  saved,
  onProviderChange,
  onEndpointChange,
  onModelChange,
  onApiVersionChange,
  onUrlPaste,
  onSave,
  onTest,
}: AiProviderPanelProps) {
  return (
    <div className={PANEL_CLASS}>
      <h2 className="flex items-center text-sm font-semibold uppercase tracking-[0.18em] text-gray-700 dark:text-gray-200">
        AI Provider{" "}
        <InfoTooltip content="Configure the AI service used for generating resource skill profile summaries. Either OpenAI directly or Azure OpenAI Service." />
      </h2>

      <div>
        <label className={LABEL_CLASS}>Provider</label>
        <div className="flex w-fit overflow-hidden rounded-xl border border-gray-200 dark:border-gray-600">
          <button
            type="button"
            onClick={() => onProviderChange("openai")}
            className={`px-4 py-2 text-sm font-semibold transition-colors ${
              provider === "openai"
                ? "bg-brand-600 text-white"
                : "bg-white text-gray-600 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
            }`}
          >
            OpenAI
          </button>
          <button
            type="button"
            onClick={() => onProviderChange("azure")}
            className={`border-l border-gray-200 px-4 py-2 text-sm font-semibold transition-colors dark:border-gray-600 ${
              provider === "azure"
                ? "bg-brand-600 text-white"
                : "bg-white text-gray-600 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
            }`}
          >
            Azure OpenAI
          </button>
        </div>
        <p className="mt-1.5 text-xs text-gray-400 dark:text-gray-500">
          {provider === "openai"
            ? "Use a standard OpenAI API key from platform.openai.com."
            : "Use a deployment on your own Azure OpenAI resource."}
        </p>
      </div>

      {provider === "azure" ? (
        <>
          <div className="space-y-2 rounded-2xl border border-blue-200 bg-blue-50 px-4 py-3 dark:border-blue-700 dark:bg-blue-900/20">
            <p className="text-xs font-medium text-blue-800 dark:text-blue-300">
              Paste a full completion URL to auto-fill all fields below:
            </p>
            <input
              type="url"
              className={`${INPUT_CLASS} border-blue-300 dark:border-blue-600`}
              placeholder="https://…cognitiveservices.azure.com/openai/deployments/gpt-5/chat/completions?api-version=2025-01-01-preview"
              value={urlPasteValue}
              onChange={(event) => onUrlPaste(event.target.value)}
            />
            {urlParseError ? (
              <p className="text-xs text-red-600 dark:text-red-400">
                Could not parse URL; expected either a Chat Completions URL (
                <code className="font-mono">/openai/deployments/…/chat/completions</code>) or a
                Responses API URL (<code className="font-mono">/openai/responses</code>).
              </p>
            ) : null}
            {urlParsedType === "responses" ? (
              <p className="text-xs text-amber-700 dark:text-amber-400">
                Responses API URL detected. Endpoint and api-version were filled in, but the
                deployment or model name still has to be entered manually below.
              </p>
            ) : null}
            {urlParsedType === "completions" ? (
              <p className="text-xs text-green-700 dark:text-green-400">
                All fields filled from URL.
              </p>
            ) : null}
          </div>

          <div>
            <label className={LABEL_CLASS} htmlFor="ai-endpoint">
              Endpoint (base URL)
            </label>
            <input
              id="ai-endpoint"
              type="url"
              className={INPUT_CLASS}
              placeholder="https://myinstance.cognitiveservices.azure.com"
              value={endpoint}
              onChange={(event) => onEndpointChange(event.target.value)}
            />
            <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
              Everything up to (not including) <code className="font-mono">/openai/…</code>
            </p>
          </div>
        </>
      ) : null}

      <div>
        <label className={LABEL_CLASS} htmlFor="ai-model">
          {provider === "azure" ? "Deployment Name" : "Model Name"}
        </label>
        <input
          id="ai-model"
          type="text"
          className={INPUT_CLASS}
          placeholder={provider === "azure" ? "nexus-gpt-5-4" : DEFAULT_OPENAI_MODEL}
          value={model}
          onChange={(event) => onModelChange(event.target.value)}
        />
        <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
          {provider === "azure"
            ? "The deployment name chosen when deploying the model in Azure."
            : `The model identifier, for example ${DEFAULT_OPENAI_MODEL} or gpt-5.4-pro.`}
        </p>
      </div>

      {provider === "azure" ? (
        <div>
          <label className={LABEL_CLASS} htmlFor="ai-api-version">
            API Version
          </label>
          <input
            id="ai-api-version"
            type="text"
            className={INPUT_CLASS}
            placeholder="2025-01-01-preview"
            value={apiVersion}
            onChange={(event) => onApiVersionChange(event.target.value)}
          />
          <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
            The <code className="font-mono">api-version</code> query parameter from the endpoint
            URL. Default: <code className="font-mono">2025-01-01-preview</code>
          </p>
        </div>
      ) : null}

      <RuntimeSecretCard
        title="Primary AI API Key"
        description={
          provider === "openai"
            ? "The runtime reads the OpenAI key directly from deployment secrets. Saving this form does not store or rotate secrets."
            : "The runtime reads the Azure OpenAI key directly from deployment secrets. Saving this form only updates non-secret metadata."
        }
        secret={runtimeSecret}
        optionalNote={
          provider === "openai"
            ? "Expected source: OPENAI_API_KEY. AZURE_OPENAI_API_KEY is also accepted as a fallback."
            : "Expected source: AZURE_OPENAI_API_KEY. OPENAI_API_KEY is also accepted as a fallback."
        }
      />

      {testResult ? (
        <div
          className={`rounded-2xl border px-4 py-3 text-sm ${
            testResult.ok
              ? "border-green-200 bg-green-50 text-green-700 dark:border-green-700 dark:bg-green-900/30 dark:text-green-300"
              : "border-red-200 bg-red-50 text-red-700 dark:border-red-700 dark:bg-red-900/30 dark:text-red-300"
          }`}
        >
          {testResult.ok ? (
            <span className="font-medium">
              Connection successful. AI summaries are ready to use.
            </span>
          ) : (
            <div className="space-y-2">
              <p>
                <span className="font-medium">Connection failed:</span> {testResult.error}
              </p>
            </div>
          )}
        </div>
      ) : null}

      <div className="flex items-center gap-3 pt-2">
        <button type="button" onClick={onSave} disabled={isSaving} className={PRIMARY_BUTTON_CLASS}>
          {isSaving ? "Saving…" : "Save Settings"}
        </button>
        <button
          type="button"
          onClick={onTest}
          disabled={isTesting}
          className={SECONDARY_BUTTON_CLASS}
        >
          {isTesting ? "Testing…" : "Test Connection"}
        </button>
        {saved ? (
          <span className="text-sm font-medium text-green-600 dark:text-green-400">Saved!</span>
        ) : null}
      </div>
    </div>
  );
}

type GenerationSettingsPanelProps = {
  maxTokens: number;
  temperature: number;
  summaryPrompt: string;
  defaultSummaryPrompt: string;
  isSaving: boolean;
  saved: boolean;
  onMaxTokensChange: (value: number) => void;
  onTemperatureChange: (value: number) => void;
  onSummaryPromptChange: (value: string) => void;
  onSave: () => void;
  onResetSummaryPrompt: () => void;
};

export function GenerationSettingsPanel({
  maxTokens,
  temperature,
  summaryPrompt,
  defaultSummaryPrompt,
  isSaving,
  saved,
  onMaxTokensChange,
  onTemperatureChange,
  onSummaryPromptChange,
  onSave,
  onResetSummaryPrompt,
}: GenerationSettingsPanelProps) {
  return (
    <div className={PANEL_CLASS}>
      <h2 className="flex items-center text-sm font-semibold uppercase tracking-[0.18em] text-gray-700 dark:text-gray-200">
        Generation Settings{" "}
        <InfoTooltip content="Fine-tune how the AI generates skill profile summaries. These settings affect output length, creativity, and the prompt template." />
      </h2>

      <div>
        <div className="mb-1 flex items-center justify-between">
          <label className={LABEL_CLASS} htmlFor="ai-max-tokens">
            Max Completion Tokens
          </label>
          <span className="text-sm font-mono text-brand-600 dark:text-brand-400">{maxTokens}</span>
        </div>
        <input
          id="ai-max-tokens"
          type="range"
          min={50}
          max={2000}
          step={50}
          value={maxTokens}
          onChange={(event) => onMaxTokensChange(Number(event.target.value))}
          className="w-full accent-brand-600"
        />
        <div className="mt-1 flex justify-between text-xs text-gray-400">
          <span>500</span>
          <span className="text-gray-500 dark:text-gray-400">
            {maxTokens < 1000
              ? "⚠ May be empty for reasoning models (GPT-5, o1, o3)"
              : maxTokens <= 2000
                ? "Recommended for reasoning models ✓"
                : maxTokens <= 4000
                  ? "High; allows longer bios"
                  : "Very high"}
          </span>
          <span>16000</span>
        </div>
        <p className="mt-1 text-xs text-amber-600 dark:text-amber-400">
          Reasoning models consume tokens internally before writing output. Keep this at 2000 or
          above to avoid empty responses.
        </p>
      </div>

      <div>
        <div className="mb-1 flex items-center justify-between">
          <label className={LABEL_CLASS} htmlFor="ai-temperature">
            Temperature
          </label>
          <span className="text-sm font-mono text-brand-600 dark:text-brand-400">
            {temperature.toFixed(1)}
          </span>
        </div>
        <input
          id="ai-temperature"
          type="range"
          min={0}
          max={2}
          step={0.1}
          value={temperature}
          onChange={(event) => onTemperatureChange(Number(event.target.value))}
          className="w-full accent-brand-600"
        />
        <div className="mt-1 flex justify-between text-xs text-gray-400">
          <span>0 — deterministic</span>
          <span className="text-gray-500 dark:text-gray-400">
            {temperature <= 0.3
              ? "Factual & consistent"
              : temperature <= 0.9
                ? "Balanced"
                : temperature <= 1.0
                  ? "Default (1) — recommended ✓"
                  : temperature <= 1.2
                    ? "Creative"
                    : "Very creative / unpredictable"}
          </span>
          <span>2 — creative</span>
        </div>
        <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
          Some models only accept the default value of 1. If generation fails with a temperature
          error, the system retries automatically without it.
        </p>
      </div>

      <div>
        <div className="mb-1 flex items-center justify-between">
          <label className={LABEL_CLASS} htmlFor="ai-prompt">
            Profile Summary Prompt
          </label>
          {summaryPrompt ? (
            <button
              type="button"
              onClick={onResetSummaryPrompt}
              className="text-xs text-brand-600 hover:underline"
            >
              Reset to default
            </button>
          ) : null}
        </div>
        <textarea
          id="ai-prompt"
          rows={10}
          value={summaryPrompt || defaultSummaryPrompt}
          onChange={(event) => onSummaryPromptChange(event.target.value)}
          className={`${INPUT_CLASS} resize-y font-mono text-xs leading-relaxed`}
          spellCheck={false}
        />
        <p className="mt-1 text-xs text-gray-400 dark:text-gray-500">
          Available placeholders: <code className="font-mono">{"{role}"}</code>{" "}
          <code className="font-mono">{"{chapter}"}</code>{" "}
          <code className="font-mono">{"{mainSkills}"}</code>{" "}
          <code className="font-mono">{"{topSkills}"}</code>
        </p>
      </div>

      <div className="flex items-center gap-3 pt-1">
        <button type="button" onClick={onSave} disabled={isSaving} className={PRIMARY_BUTTON_CLASS}>
          {isSaving ? "Saving…" : "Save Settings"}
        </button>
        {saved ? (
          <span className="text-sm font-medium text-green-600 dark:text-green-400">Saved!</span>
        ) : null}
      </div>
    </div>
  );
}
