import { useEffect } from 'react';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import type { ModelOption } from 'state/useModels';
import { getProviderDisplayName } from 'state/useModels';
import type { ChatMessage } from '../types';

const PROVIDER_DISPLAY: Record<string, string> = {
  anthropic: 'Anthropic',
  openai: 'OpenAI',
  google: 'Google',
  groq: 'Groq',
  mistral: 'Mistral',
  xai: 'xAI',
  openrouter: 'OpenRouter',
  huggingface: 'Hugging Face',
  'github-copilot': 'GitHub Copilot',
  minimax: 'MiniMax',
  bedrock: 'Amazon Bedrock',
  'google-vertex': 'Google Vertex AI',
  'azure-openai': 'Azure OpenAI',
  'claude-code': 'Claude Code',
  opencode: 'OpenCode Zen',
};

type ModelSelectorProps = {
  messages: ChatMessage[];
  availableModels: ModelOption[];
  selectedModel: string | null;
  onModelChange: (modelId: string) => void;
  model: string | null;
  isConnected: boolean;
  isGenerating: boolean;
  hasStarted: boolean;
  /**
   * Still accepted so no call site has to change, and deliberately unread: the control they drove was
   * removed because nothing forwarded `thinking` to either harness. Delete both when the rest of the
   * plumbing goes.
   */
  thinkingLevel?: string | null;
  onThinkingChange?: (level: string | null) => void;
};

export function ModelSelector({
  messages,
  availableModels,
  selectedModel,
  onModelChange,
  model,
  isConnected,
  isGenerating,
  hasStarted,
}: ModelSelectorProps) {
  const providers = [...new Set(availableModels.map((m) => m.provider).filter(Boolean))] as string[];

  // Determine which model to display: selectedModel takes precedence, then model (from server), then fallback
  const displayModel = selectedModel || model;

  const activeProvider = availableModels.find((m) => m.id === displayModel)?.provider ?? providers[0];
  const providerModels = availableModels.filter((m) => m.provider === activeProvider);
  const fallbackModelId = providerModels[0]?.id ?? null;

  // Sync actual selection when UI shows a fallback provider but nothing is selected
  useEffect(() => {
    if (!selectedModel && !model && fallbackModelId) {
      onModelChange(fallbackModelId);
    }
  }, [selectedModel, model, fallbackModelId]);

  // Lock after session has started
  const isLocked = hasStarted || isGenerating || !isConnected;

  const handleProviderClick = (provider: string) => {
    if (isLocked) return;
    const firstModel = availableModels.find((m) => m.provider === provider);
    if (firstModel) onModelChange(firstModel.id);
  };

  const displayName = (provider: string) => {
    // Handle local providers (officer-local-{uuid})
    if (provider.startsWith('officer-local-')) {
      return getProviderDisplayName(provider);
    }
    return PROVIDER_DISPLAY[provider] ?? provider;
  };

  // Get display text for the model
  const getModelDisplayText = () => {
    if (displayModel) {
      const found = availableModels.find((m) => m.id === displayModel);
      return found?.name || displayModel;
    }
    return 'Select model';
  };

  return (
    <div className="mt-2 flex items-center justify-between gap-2">
      {isLocked ? (
        // A static label, not an action — `bg-muted` rather than a filled accent. It used to be
        // `bg-duck-dark/80 text-white`, and --duck-dark is near-white in dark mode, so this was white
        // on white for every session that had already started, i.e. almost always.
        <span className="shrink-0 truncate rounded-md bg-muted px-3 py-1 text-xs font-medium text-foreground">
          {activeProvider ? displayName(activeProvider) : 'Chat'}
        </span>
      ) : (
        // Fifteen providers can be configured and the names are long ("Google Vertex AI"), so the strip
        // scrolls rather than crushing the model select beside it.
        <div className="flex min-w-0 items-center gap-1 overflow-x-auto rounded-lg bg-background/60 p-1">
          {providers.map((provider) => (
            <button
              key={provider}
              onClick={() => handleProviderClick(provider)}
              className={`shrink-0 rounded-md px-3 py-1 text-xs font-medium transition-colors cursor-pointer ${
                activeProvider === provider
                  ? 'bg-primary text-primary-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
            >
              {displayName(provider)}
            </button>
          ))}
        </div>
      )}
      {/* The thinking toggle used to render here. It is gone because it did nothing: `thinking` is
          accepted on the wire (types.ts, websocket.ts) and forwarded by NEITHER channel — not
          send-claude-code.ts, not send-opencode.ts — so pressing it changed the label and nothing else.
          A control that lies is worse than an absent one.

          Out of scope for both harnesses by decision (parity doc, 2026-08-10), so this is a removal
          rather than a stopgap. The plumbing under it (`thinkingLevel` through useChat /
          useEmbeddableChat, `ThinkingLevel` in types.ts) is still threaded and still inert; deleting it
          is a separate change that touches the socket contract. */}
      <div className="flex min-w-0 shrink-0 items-center gap-2">
        <div className="min-w-0 text-xs text-muted-foreground">
          {providerModels.length > 0 ? (
            <Select
              value={displayModel ?? fallbackModelId ?? undefined}
              onValueChange={(v) => !isLocked && onModelChange(v)}
              disabled={isLocked}
            >
              <SelectTrigger className="h-auto cursor-pointer gap-1 border-0 bg-transparent p-0 text-xs text-muted-foreground shadow-none focus:ring-0">
                <SelectValue />
              </SelectTrigger>
              <SelectContent className="z-[800]" side="top">
                {providerModels.map((m) => (
                  <SelectItem key={m.id} value={m.id}>
                    {m.name}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          ) : (
            <span>{getModelDisplayText()}</span>
          )}
        </div>
      </div>
    </div>
  );
}
