import { useState, useEffect, useContext } from 'react';
import { useConfig } from '@/contexts/ConfigContext';
import { AppBarContext } from '@/contexts/AppBarContext';
import { components } from '@/api/v1/schema';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from '@/components/ui/dialog';
import { Switch } from '@/components/ui/switch';
import { ProviderAuthCard } from '@/features/agent/components/ProviderAuthCard';
import {
  AGENT_MODEL_PROVIDERS,
  type AgentModelProvider,
  getAgentModelProviderMeta,
} from '@/features/agent/modelProviders';
import { getAuthHeaders } from '@/lib/authHeaders';

type ModelConfig = components['schemas']['ModelConfigResponse'];
type ModelPreset = components['schemas']['ModelPreset'];
type AgentAuthProviderStatus = components['schemas']['AgentAuthProviderStatus'];
type StartAgentAuthProviderLoginResponse = components['schemas']['StartAgentAuthProviderLoginResponse'];
type CompleteAgentAuthProviderLoginRequest = components['schemas']['CompleteAgentAuthProviderLoginRequest'];

// Mirrors internal/agent/store.go:GenerateSlugID
function generateSlugId(name: string): string {
  return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
}

const REASONING_DEFAULT_VALUE = '__default__';
const REASONING_EFFORT_OPTIONS = [
  { value: REASONING_DEFAULT_VALUE, label: 'Provider default' },
  { value: 'low', label: 'Low' },
  { value: 'medium', label: 'Medium' },
  { value: 'high', label: 'High' },
  { value: 'xhigh', label: 'XHigh' },
];

interface ModelFormModalProps {
  open: boolean;
  model?: ModelConfig;
  presets: ModelPreset[];
  codexProvider: AgentAuthProviderStatus | null;
  codexAuthLoading?: boolean;
  onStartProviderLogin: (providerId: string) => Promise<StartAgentAuthProviderLoginResponse>;
  onCompleteProviderLogin: (
    providerId: string,
    body: CompleteAgentAuthProviderLoginRequest
  ) => Promise<AgentAuthProviderStatus | null>;
  onDisconnectProvider: (providerId: string) => Promise<void>;
  onClose: () => void;
  onSuccess: () => void;
}

export function ModelFormModal({
  open,
  model,
  presets,
  codexProvider,
  codexAuthLoading = false,
  onStartProviderLogin,
  onCompleteProviderLogin,
  onDisconnectProvider,
  onClose,
  onSuccess,
}: ModelFormModalProps) {
  const config = useConfig();
  const appBarContext = useContext(AppBarContext);
  const isEditing = !!model;

  const [configId, setConfigId] = useState('');
  const [customId, setCustomId] = useState(false);
  const [name, setName] = useState('');
  const [provider, setProvider] = useState<AgentModelProvider>('anthropic');
  const [modelId, setModelId] = useState('');
  const [apiKey, setApiKey] = useState('');
  const [clearStoredAPIKey, setClearStoredAPIKey] = useState(false);
  const [baseUrl, setBaseUrl] = useState('');
  const [description, setDescription] = useState('');
  const [contextWindow, setContextWindow] = useState<number | ''>('');
  const [maxOutputTokens, setMaxOutputTokens] = useState<number | ''>('');
  const [inputCostPer1M, setInputCostPer1M] = useState<number | ''>('');
  const [outputCostPer1M, setOutputCostPer1M] = useState<number | ''>('');
  const [supportsThinking, setSupportsThinking] = useState(false);
  const [thinkingEffort, setThinkingEffort] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const providerMeta = getAgentModelProviderMeta(provider);
  const usesSubscriptionAuth = providerMeta.authMode === 'subscription';
  const codexConnected = codexProvider?.connected ?? false;

  useEffect(() => {
    if (open && model) {
      setConfigId(model.id);
      setName(model.name);
      setProvider(model.provider);
      setModelId(model.model);
      setBaseUrl(model.baseUrl ?? '');
      setDescription(model.description ?? '');
      setContextWindow(model.contextWindow ?? '');
      setMaxOutputTokens(model.maxOutputTokens ?? '');
      setInputCostPer1M(model.inputCostPer1M ?? '');
      setOutputCostPer1M(model.outputCostPer1M ?? '');
      setSupportsThinking(model.supportsThinking ?? false);
      setThinkingEffort(model.thinkingEffort ?? '');
      setApiKey('');
      setClearStoredAPIKey(false);
    } else if (open && !model) {
      resetForm();
    }
    if (open) {
      setError(null);
    }
  }, [open, model]);

  function resetForm() {
    setConfigId('');
    setCustomId(false);
    setName('');
    setProvider('anthropic');
    setModelId('');
    setApiKey('');
    setClearStoredAPIKey(false);
    setBaseUrl('');
    setDescription('');
    setContextWindow('');
    setMaxOutputTokens('');
    setInputCostPer1M('');
    setOutputCostPer1M('');
    setSupportsThinking(false);
    setThinkingEffort('');
  }

  const handlePresetSelect = (presetName: string) => {
    const preset = presets.find((p) => p.name === presetName);
    if (preset) {
      setCustomId(false);
      setConfigId(generateSlugId(preset.name));
      setName(preset.name);
      setProvider(preset.provider);
      setModelId(preset.model);
      setDescription(preset.description ?? '');
      setContextWindow(preset.contextWindow ?? '');
      setMaxOutputTokens(preset.maxOutputTokens ?? '');
      setInputCostPer1M(preset.inputCostPer1M ?? '');
      setOutputCostPer1M(preset.outputCostPer1M ?? '');
      setSupportsThinking(preset.supportsThinking ?? false);
      setThinkingEffort(preset.thinkingEffort ?? '');
      setApiKey('');
      setClearStoredAPIKey(false);
      setBaseUrl('');
    }
  };

  useEffect(() => {
    if (usesSubscriptionAuth) {
      setApiKey('');
      setClearStoredAPIKey(false);
      setBaseUrl('');
    }
  }, [usesSubscriptionAuth]);

  useEffect(() => {
    if (!supportsThinking) {
      setThinkingEffort('');
    }
  }, [supportsThinking]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setIsLoading(true);
    setError(null);

    try {
      if (usesSubscriptionAuth && !codexConnected) {
        throw new Error('Connect OpenAI Codex before saving this model');
      }

      const remoteNode = encodeURIComponent(appBarContext.selectedRemoteNode || 'local');

      const body: Record<string, unknown> = {
        id: !isEditing && configId ? configId : undefined,
        name,
        provider,
        model: modelId,
        description: description || undefined,
        contextWindow: contextWindow !== '' ? contextWindow : undefined,
        maxOutputTokens: maxOutputTokens !== '' ? maxOutputTokens : undefined,
        inputCostPer1M: inputCostPer1M !== '' ? inputCostPer1M : undefined,
        outputCostPer1M: outputCostPer1M !== '' ? outputCostPer1M : undefined,
        supportsThinking,
        thinkingEffort: supportsThinking ? thinkingEffort : '',
      };

      const trimmedBaseURL = baseUrl.trim();
      if (!usesSubscriptionAuth && trimmedBaseURL !== '') {
        body.baseUrl = trimmedBaseURL;
      }

      if (!usesSubscriptionAuth && apiKey) {
        body.apiKey = apiKey;
      } else if (!usesSubscriptionAuth && isEditing && clearStoredAPIKey) {
        body.apiKey = '';
      }

      const url = isEditing
        ? `${config.apiURL}/settings/agent/models/${model.id}?remoteNode=${remoteNode}`
        : `${config.apiURL}/settings/agent/models?remoteNode=${remoteNode}`;

      const response = await fetch(url, {
        method: isEditing ? 'PATCH' : 'POST',
        headers: getAuthHeaders(),
        body: JSON.stringify(body),
      });

      if (!response.ok) {
        const data = await response.json().catch(() => ({}));
        throw new Error(data.message || `Failed to ${isEditing ? 'update' : 'create'} model`);
      }

      resetForm();
      onSuccess();
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onClose}>
      <DialogContent className="sm:max-w-lg max-h-[90vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>{isEditing ? 'Edit Model' : 'Add Model'}</DialogTitle>
          <DialogDescription className="sr-only">
            Configure the model settings used by the agent.
          </DialogDescription>
        </DialogHeader>
        <form onSubmit={handleSubmit}>
          <div className="space-y-3 py-3">
            {error && (
              <div className="p-3 text-sm text-destructive bg-destructive/10 rounded-md">
                {error}
              </div>
            )}

            {!isEditing && presets.length > 0 && (
              <div className="space-y-1.5">
                <Label className="text-sm">Import from Preset</Label>
                <Select onValueChange={handlePresetSelect}>
                  <SelectTrigger className="h-8">
                    <SelectValue placeholder="Select a preset..." />
                  </SelectTrigger>
                  <SelectContent>
                    {presets.map((p) => (
                      <SelectItem key={p.name} value={p.name}>
                        {p.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            )}

            <div className="space-y-1.5">
              <Label htmlFor="model-name" className="text-sm">Name</Label>
              <Input
                id="model-name"
                value={name}
                onChange={(e) => {
                  const v = e.target.value;
                  setName(v);
                  if (!isEditing && !customId) {
                    setConfigId(generateSlugId(v));
                  }
                }}
                placeholder="My Model"
                className="h-8"
                required
              />
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="model-config-id" className="text-sm">ID {isEditing ? '' : '(optional)'}</Label>
              <Input
                id="model-config-id"
                value={configId}
                onChange={(e) => {
                  setConfigId(e.target.value);
                  setCustomId(true);
                }}
                placeholder="Auto-generated from name if empty"
                className="h-8"
                readOnly={isEditing}
                disabled={isEditing}
              />
              {!isEditing && (
                <p className="text-xs text-muted-foreground">
                  Lowercase letters, numbers, and hyphens only
                </p>
              )}
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="model-provider" className="text-sm">Provider</Label>
              <Select
                value={provider}
                onValueChange={(value) => setProvider(value as AgentModelProvider)}
              >
                <SelectTrigger id="model-provider" className="h-8">
                  <SelectValue placeholder="Select provider" />
                </SelectTrigger>
                <SelectContent>
                  {AGENT_MODEL_PROVIDERS.map((p) => (
                    <SelectItem key={p.value} value={p.value}>
                      {p.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="model-id" className="text-sm">Model</Label>
              <Input
                id="model-id"
                value={modelId}
                onChange={(e) => setModelId(e.target.value)}
                placeholder={providerMeta.modelPlaceholder}
                className="h-8"
                required
              />
            </div>

            {usesSubscriptionAuth ? (
              codexProvider ? (
                <ProviderAuthCard
                  provider={codexProvider}
                  compact
                  isLoading={codexAuthLoading}
                  onStartLogin={onStartProviderLogin}
                  onCompleteLogin={onCompleteProviderLogin}
                  onDisconnect={onDisconnectProvider}
                />
              ) : (
                <div className="rounded-md border border-dashed border-border/80 p-3 text-sm text-muted-foreground">
                  {codexAuthLoading ? 'Loading OpenAI Codex connection...' : 'OpenAI Codex connection status is unavailable.'}
                </div>
              )
            ) : (
              <>
                <div className="space-y-1.5">
                  <Label htmlFor="model-api-key" className="text-sm">
                    {providerMeta.apiKeyMode === 'optional'
                      ? 'API Key (optional)'
                      : 'API Key'}
                  </Label>
                  <Input
                    id="model-api-key"
                    type="password"
                    value={apiKey}
                    onChange={(e) => {
                      setApiKey(e.target.value);
                      if (clearStoredAPIKey) {
                        setClearStoredAPIKey(false);
                      }
                    }}
                    placeholder={isEditing && model?.apiKeyConfigured ? '********' : 'Enter API key'}
                    className="h-8"
                    disabled={clearStoredAPIKey}
                  />
                  {providerMeta.apiKeyHelperText && (
                    <p className="text-xs text-muted-foreground">
                      {providerMeta.apiKeyHelperText}
                    </p>
                  )}
                  {isEditing && model?.apiKeyConfigured && !clearStoredAPIKey && (
                    <p className="text-xs text-muted-foreground">
                      Leave empty to keep existing key, or clear it below.
                    </p>
                  )}
                  {isEditing && model?.apiKeyConfigured && (
                    <div className="flex items-center gap-2">
                      <Checkbox
                        id="clear-api-key"
                        checked={clearStoredAPIKey}
                        onCheckedChange={(checked) => {
                          const enabled = checked === true;
                          setClearStoredAPIKey(enabled);
                          if (enabled) {
                            setApiKey('');
                          }
                        }}
                      />
                      <Label htmlFor="clear-api-key" className="text-xs">
                        Clear stored API key
                      </Label>
                    </div>
                  )}
                  {clearStoredAPIKey && (
                    <p className="text-xs text-muted-foreground">
                      Save changes to remove the stored key.
                    </p>
                  )}
                </div>

                <div className="space-y-1.5">
                  <Label htmlFor="model-base-url" className="text-sm">Base URL (optional)</Label>
                  <Input
                    id="model-base-url"
                    value={baseUrl}
                    onChange={(e) => setBaseUrl(e.target.value)}
                    placeholder={
                      providerMeta.baseUrlPlaceholder ?? 'Custom API endpoint'
                    }
                    className="h-8"
                  />
                </div>
              </>
            )}

            <div className="space-y-1.5">
              <Label htmlFor="model-description" className="text-sm">Description (optional)</Label>
              <Input
                id="model-description"
                value={description}
                onChange={(e) => setDescription(e.target.value)}
                placeholder="Description"
                className="h-8"
              />
            </div>

            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1.5">
                <Label htmlFor="model-context-window" className="text-sm">Context Window (optional)</Label>
                <Input
                  id="model-context-window"
                  type="number"
                  min={0}
                  value={contextWindow}
                  onChange={(e) => setContextWindow(e.target.value ? Number(e.target.value) : '')}
                  placeholder="e.g. 200000"
                  className="h-8"
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="model-max-output" className="text-sm">Max Output Tokens (optional)</Label>
                <Input
                  id="model-max-output"
                  type="number"
                  min={0}
                  value={maxOutputTokens}
                  onChange={(e) => setMaxOutputTokens(e.target.value ? Number(e.target.value) : '')}
                  placeholder="e.g. 128000"
                  className="h-8"
                />
              </div>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1.5">
                <Label htmlFor="model-input-cost" className="text-sm">Input Cost / 1M tokens (optional)</Label>
                <Input
                  id="model-input-cost"
                  type="number"
                  min={0}
                  step="0.01"
                  value={inputCostPer1M}
                  onChange={(e) => setInputCostPer1M(e.target.value ? Number(e.target.value) : '')}
                  placeholder="e.g. 3.00"
                  className="h-8"
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="model-output-cost" className="text-sm">Output Cost / 1M tokens (optional)</Label>
                <Input
                  id="model-output-cost"
                  type="number"
                  min={0}
                  step="0.01"
                  value={outputCostPer1M}
                  onChange={(e) => setOutputCostPer1M(e.target.value ? Number(e.target.value) : '')}
                  placeholder="e.g. 15.00"
                  className="h-8"
                />
              </div>
            </div>

            <div className="flex items-center justify-between">
              <Label htmlFor="model-thinking" className="text-sm">Supports Thinking (optional)</Label>
              <Switch
                id="model-thinking"
                checked={supportsThinking}
                onCheckedChange={setSupportsThinking}
              />
            </div>

            {supportsThinking && (
              <div className="space-y-1.5">
                <Label htmlFor="model-thinking-effort" className="text-sm">Reasoning Effort</Label>
                <Select
                  value={thinkingEffort || REASONING_DEFAULT_VALUE}
                  onValueChange={(value) => setThinkingEffort(value === REASONING_DEFAULT_VALUE ? '' : value)}
                >
                  <SelectTrigger id="model-thinking-effort" className="h-8">
                    <SelectValue placeholder="Select reasoning effort" />
                  </SelectTrigger>
                  <SelectContent>
                    {REASONING_EFFORT_OPTIONS.map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            )}
          </div>

          <DialogFooter>
            <Button type="button" variant="outline" onClick={onClose} size="sm" className="h-8">
              Cancel
            </Button>
            <Button
              type="submit"
              disabled={isLoading || !name || !modelId || (usesSubscriptionAuth && !codexConnected)}
              size="sm"
              className="h-8"
            >
              {isLoading ? 'Saving...' : isEditing ? 'Save Changes' : 'Add Model'}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}
