import * as api from "@client/api";
import { useDemoInfo } from "@client/hooks/useDemoInfo";
import { useSettings } from "@client/hooks/useSettings";
import { SettingsInput } from "@client/pages/settings/components/SettingsInput";
import {
  getLlmProviderConfig,
  LLM_PROVIDER_LABELS,
  LLM_PROVIDERS,
  normalizeLlmProvider,
} from "@client/pages/settings/utils";
import { getDefaultModelForProvider } from "@shared/settings-registry";
import type { UpdateSettingsInput } from "@shared/settings-schema.js";
import type { ValidationResult } from "@shared/types.js";
import { Check } from "lucide-react";
import type React from "react";
import { useCallback, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { toast } from "sonner";
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
  FieldTitle,
} from "@/components/ui/field";
import { Progress } from "@/components/ui/progress";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";

type ValidationState = ValidationResult & { checked: boolean };

type OnboardingFormData = {
  llmProvider: string;
  llmBaseUrl: string;
  llmApiKey: string;
};

const EMPTY_VALIDATION_STATE: ValidationState = {
  valid: false,
  message: null,
  checked: false,
};

export const OnboardingGate: React.FC = () => {
  const {
    settings,
    isLoading: settingsLoading,
    refreshSettings,
  } = useSettings();

  const [isSavingEnv, setIsSavingEnv] = useState(false);
  const [isValidatingLlm, setIsValidatingLlm] = useState(false);
  const [llmValidation, setLlmValidation] = useState<ValidationState>(
    EMPTY_VALIDATION_STATE,
  );
  const demoInfo = useDemoInfo();
  const demoMode = demoInfo?.demoMode ?? false;

  const { control, watch, getValues, reset, setValue } =
    useForm<OnboardingFormData>({
      defaultValues: {
        llmProvider: "",
        llmBaseUrl: "",
        llmApiKey: "",
      },
    });

  const llmProvider = watch("llmProvider");

  const validateLlm = useCallback(async () => {
    const values = getValues();
    const selectedProvider = normalizeLlmProvider(
      values.llmProvider || settings?.llmProvider?.value || "openrouter",
    );
    const providerConfig = getLlmProviderConfig(selectedProvider);
    const { requiresApiKey, showBaseUrl } = providerConfig;

    setIsValidatingLlm(true);
    try {
      const result = await api.validateLlm({
        provider: selectedProvider,
        baseUrl: showBaseUrl
          ? values.llmBaseUrl.trim() || undefined
          : undefined,
        apiKey: requiresApiKey
          ? values.llmApiKey.trim() || undefined
          : undefined,
      });
      setLlmValidation({ ...result, checked: true });
      return result;
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "LLM validation failed";
      const result = { valid: false, message };
      setLlmValidation({ ...result, checked: true });
      return result;
    } finally {
      setIsValidatingLlm(false);
    }
  }, [getValues, settings?.llmProvider]);

  const selectedProvider = normalizeLlmProvider(
    llmProvider || settings?.llmProvider?.value || "openrouter",
  );
  const providerConfig = getLlmProviderConfig(selectedProvider);
  const {
    normalizedProvider,
    showApiKey,
    showBaseUrl,
    requiresApiKey: requiresLlmKey,
  } = providerConfig;

  const llmKeyHint = settings?.llmApiKeyHint ?? null;
  const hasLlmKey = Boolean(llmKeyHint);
  const llmValidated = requiresLlmKey ? llmValidation.valid : true;

  const hasCheckedValidations = requiresLlmKey ? llmValidation.checked : true;

  const shouldOpen =
    !demoMode &&
    Boolean(settings && !settingsLoading) &&
    hasCheckedValidations &&
    !llmValidated;

  useEffect(() => {
    if (settings) {
      reset({
        llmProvider: settings.llmProvider?.value || "",
        llmBaseUrl: settings.llmBaseUrl?.value || "",
        llmApiKey: "",
      });
    }
  }, [settings, reset]);

  useEffect(() => {
    if (!showBaseUrl) {
      setValue("llmBaseUrl", "");
    }
  }, [showBaseUrl, setValue]);

  useEffect(() => {
    if (!selectedProvider) return;
    setLlmValidation({ valid: false, message: null, checked: false });
  }, [selectedProvider]);

  const runLlmValidation = useCallback(async () => {
    if (!settings) return;
    if (requiresLlmKey) {
      await validateLlm();
    } else {
      setLlmValidation({ valid: true, message: null, checked: true });
    }
  }, [settings, requiresLlmKey, validateLlm]);

  useEffect(() => {
    if (demoMode) return;
    if (!settings || settingsLoading) return;
    if (requiresLlmKey ? llmValidation.checked : true) return;
    void runLlmValidation();
  }, [
    settings,
    settingsLoading,
    requiresLlmKey,
    llmValidation.checked,
    runLlmValidation,
    demoMode,
  ]);

  const handleSaveLlm = async () => {
    const values = getValues();
    const apiKeyValue = values.llmApiKey.trim();
    const baseUrlValue = values.llmBaseUrl.trim();

    if (requiresLlmKey && !apiKeyValue && !hasLlmKey) {
      toast.info("Add your LLM API key to continue");
      return;
    }

    try {
      const validation = requiresLlmKey
        ? await validateLlm()
        : { valid: true, message: null };

      if (!validation.valid) {
        toast.error(validation.message || "LLM validation failed");
        return;
      }

      const update: Partial<UpdateSettingsInput> = {
        llmProvider: normalizedProvider,
        llmBaseUrl: showBaseUrl ? baseUrlValue || null : null,
        model: null,
        modelScorer: null,
        modelTailoring: null,
        modelProjectSelection: null,
      };

      if (showApiKey && apiKeyValue) {
        update.llmApiKey = apiKeyValue;
      }

      setIsSavingEnv(true);
      await api.updateSettings(update);
      await refreshSettings();
      setValue("llmApiKey", "");
      const defaultModel = getDefaultModelForProvider(normalizedProvider);
      toast.success("LLM provider connected", {
        description:
          normalizedProvider === "openai" || normalizedProvider === "gemini"
            ? `Default for ${providerConfig.label}: ${defaultModel}.`
            : "Select the model manually in Settings > Model.",
      });
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "Failed to save LLM settings";
      toast.error(message);
    } finally {
      setIsSavingEnv(false);
    }
  };

  const isBusy = isSavingEnv || settingsLoading || isValidatingLlm;
  const progressValue = llmValidated ? 100 : 0;

  if (!shouldOpen) return null;

  return (
    <AlertDialog open>
      <AlertDialogContent
        className="max-w-3xl max-h-[90vh] overflow-hidden p-0"
        onEscapeKeyDown={(event) => event.preventDefault()}
      >
        <div className="space-y-6 px-6 py-6 max-h-[calc(90vh-3.5rem)] overflow-y-auto">
          <AlertDialogHeader>
            <AlertDialogTitle>Welcome to Job Ops</AlertDialogTitle>
            <AlertDialogDescription>
              Connect your LLM provider to run job scoring, summaries, and
              tailoring. You can add a resume file later in Settings if you need
              PDF export or resume-based scoring.
            </AlertDialogDescription>
          </AlertDialogHeader>

          <FieldLabel className="w-full [&>[data-slot=field]]:border-0 [&>[data-slot=field]]:p-0 [&>[data-slot=field]]:rounded-none">
            <div className="w-full rounded-md border-b-2 border-primary bg-muted/60 px-3 py-4 text-left">
              <Field orientation="horizontal" className="items-start">
                <FieldContent>
                  <FieldTitle>LLM Provider</FieldTitle>
                  <FieldDescription>Provider + credentials</FieldDescription>
                </FieldContent>
                <span
                  className={cn(
                    "mt-0.5 flex h-6 w-6 items-center justify-center rounded-md text-xs font-semibold",
                    llmValidated
                      ? "bg-primary text-primary-foreground"
                      : "bg-muted text-muted-foreground",
                  )}
                >
                  {llmValidated ? <Check className="h-3.5 w-3.5" /> : "1"}
                </span>
              </Field>
            </div>
          </FieldLabel>

          <div className="space-y-4 pt-2">
            <div>
              <p className="text-sm font-semibold">Connect LLM provider</p>
              <p className="text-xs text-muted-foreground">
                Used for job scoring, summaries, and tailoring.
              </p>
            </div>
            <div className="grid gap-4 md:grid-cols-2">
              <div className="space-y-2">
                <label htmlFor="llmProvider" className="text-sm font-medium">
                  Provider
                </label>
                <Controller
                  name="llmProvider"
                  control={control}
                  render={({ field }) => (
                    <Select
                      value={selectedProvider}
                      onValueChange={(value) => {
                        field.onChange(value);
                      }}
                      disabled={isSavingEnv}
                    >
                      <SelectTrigger id="llmProvider">
                        <SelectValue placeholder="Select provider" />
                      </SelectTrigger>
                      <SelectContent>
                        {LLM_PROVIDERS.map((provider) => (
                          <SelectItem key={provider} value={provider}>
                            {LLM_PROVIDER_LABELS[provider]}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  )}
                />
                <p className="text-xs text-muted-foreground">
                  {providerConfig.providerHint}
                </p>
              </div>
              {showBaseUrl && (
                <Controller
                  name="llmBaseUrl"
                  control={control}
                  render={({ field }) => (
                    <SettingsInput
                      label="LLM base URL"
                      inputProps={{
                        name: "llmBaseUrl",
                        value: field.value,
                        onChange: field.onChange,
                      }}
                      placeholder={providerConfig.baseUrlPlaceholder}
                      helper={providerConfig.baseUrlHelper}
                      current={settings?.llmBaseUrl?.value || "—"}
                      disabled={isSavingEnv}
                    />
                  )}
                />
              )}
              {showApiKey && (
                <Controller
                  name="llmApiKey"
                  control={control}
                  render={({ field }) => (
                    <SettingsInput
                      label="LLM API key"
                      inputProps={{
                        name: "llmApiKey",
                        value: field.value,
                        onChange: field.onChange,
                      }}
                      type="password"
                      placeholder="Enter key"
                      helper={
                        llmKeyHint
                          ? `${providerConfig.keyHelper}. Leave blank to use the saved key.`
                          : providerConfig.keyHelper
                      }
                      disabled={isSavingEnv}
                    />
                  )}
                />
              )}
            </div>
            {llmValidation.checked && !llmValidation.valid ? (
              <p className="text-xs text-destructive">
                {llmValidation.message ?? "LLM validation failed."}
              </p>
            ) : null}
          </div>

          <div className="flex items-center justify-end">
            <Button onClick={handleSaveLlm} disabled={isBusy}>
              {isBusy
                ? "Validating..."
                : llmValidated
                  ? "Revalidate"
                  : "Connect"}
            </Button>
          </div>
          <Progress value={progressValue} className="h-2" />
        </div>
      </AlertDialogContent>
    </AlertDialog>
  );
};
