'use client';

import type * as React from 'react';
import { useMemo } from 'react';
import { Globe } from 'lucide-react';

import {
  Combobox,
  type ComboboxOption,
  Flag,
} from '@djangocfg/ui-core/components';
import { cn } from '@djangocfg/ui-core/lib';

import { findSpeechLanguage } from '../../../input/SpeechRecognition';

import {
  WEB_SPEECH_LANGUAGES,
  countryFromTag,
  useResolvedLanguage,
  useSpeechPrefs,
} from '../../../input/SpeechRecognition';

export interface ChatHeaderLanguageButtonProps {
  /** Override aria-label. Default "Speech language". */
  ariaLabel?: string;
  /**
   * Subset of BCP-47 tags to offer. Default: every entry from the
   * Web Speech catalogue (~66 tags incl. regional variants). Pass a
   * tighter list when your backend STT only supports a subset.
   */
  allowedTags?: string[];
  /** Hide the globe-fallback icon when no flag resolves. */
  hideFallbackIcon?: boolean;
  className?: string;
}

/**
 * Compact flag-button language picker for the chat header. Built on
 * top of the ui-core `<Combobox>` — searchable autocomplete with
 * flags, ~66 BCP-47 tags from the official Chrome Web Speech demo, and
 * a custom 28×28 trigger via `renderTrigger`.
 *
 * The selection persists into `useSpeechPrefs` (zustand+localStorage)
 * so `useSpeechRecognition` picks it up as the second-priority resolver
 * value (above i18n locale, below an explicit `language` prop).
 */
export function ChatHeaderLanguageButton({
  ariaLabel = 'Speech language',
  allowedTags,
  hideFallbackIcon,
  className,
}: ChatHeaderLanguageButtonProps): React.ReactElement {
  const prefs = useSpeechPrefs();
  const active = useResolvedLanguage();

  // Flatten every dialect into one Combobox option. Display name keeps
  // the native language label; we stash the English aliases + BCP-47
  // tag + region in `description` purely as a hidden search index.
  // (We intentionally hide the description from the rendered row in
  // `renderOption` — it would just clutter the dropdown.)
  const options = useMemo<ComboboxOption[]>(() => {
    const allow = allowedTags ? new Set(allowedTags) : null;
    const out: ComboboxOption[] = [];
    for (const lang of WEB_SPEECH_LANGUAGES) {
      for (const d of lang.dialects) {
        if (allow && !allow.has(d.code)) continue;
        out.push({
          value: d.code,
          // "Русский" / "Español — Argentina" / "English — United States"
          label:
            lang.dialects.length === 1
              ? lang.name
              : `${lang.name} — ${d.region}`,
          // Search-only index: English name, BCP-47 tag, ISO, region.
          // Lets users type "russian" / "ru-RU" / "ru" / "argentina"
          // and still find the row regardless of native script.
          description: `${lang.englishName} ${d.code} ${lang.iso} ${d.region}`.toLowerCase(),
        });
      }
    }
    return out;
  }, [allowedTags]);

  return (
    <Combobox
      options={options}
      value={prefs.language ?? active}
      onValueChange={(v) => prefs.setLanguage(v || null)}
      placeholder={ariaLabel}
      searchPlaceholder="Search language…"
      filterFunction={(opt, search) => {
        const s = search.toLowerCase();
        // Match label (native script), value (BCP-47), and our packed
        // search index in description (English name + tag + region).
        return (
          opt.label.toLowerCase().includes(s) ||
          opt.value.toLowerCase().includes(s) ||
          (opt.description?.includes(s) ?? false)
        );
      }}
      // Popover width follows the trigger by default (28px → narrow).
      // Force a usable width; the popover already portals into ui-core's
      // anchored-overlay tier, above the dock — no z-index override needed.
      contentClassName="w-[280px]"
      // Custom row: country flag + native language label + BCP-47 tag.
      // ui-core Combobox default rendering only shows label/description
      // — feeding the flag here keeps every list row instantly
      // identifiable. Fallback to a neutral globe glyph when the tag
      // has no resolvable country (rare: bn-BD etc. all have flags).
      renderOption={(option) => {
        const country = countryFromTag(option.value);
        return (
          <div className="flex min-w-0 flex-1 items-center gap-2">
            {country ? (
              <Flag
                countryCode={country}
                className="h-4 w-5 shrink-0 overflow-hidden rounded-[2px] border border-border/60 ring-1 ring-black/5"
              />
            ) : (
              <Globe className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
            )}
            {/* Native-script label only — BCP-47 subtitle removed to
                keep the dropdown visually quiet. Tag + region still
                live in `description` for search. */}
            <span className="truncate text-sm">{option.label}</span>
          </div>
        );
      }}
      // Compact icon-only trigger — replaces the default wide outline
      // button. Stays the same 28×28 footprint as ChatHeaderActionButton
      // siblings (audio toggle, reset).
      renderTrigger={(selected, open) => {
        const tag = selected?.value ?? active;
        const country = countryFromTag(tag);
        const found = findSpeechLanguage(tag);
        // Tooltip copy: native language name + dialect region + tag.
        // Falls back to just the tag for unknown / custom-engine codes.
        const tooltipLabel = found
          ? `${found.language.name}${
              found.language.dialects.length > 1 ? ` — ${found.dialect.region}` : ''
            } · ${tag}`
          : tag;
        // Note on tooltip: we intentionally use the native `title`
        // attribute instead of `<Tooltip>` here. The button is already
        // wrapped by Combobox's `PopoverTrigger asChild`, and stacking
        // a second `TooltipTrigger asChild` on the same node makes
        // Radix Slot merge two competing refs/handlers — popover click
        // stops working. Native `title` is "good enough" for a single
        // status label and ships zero extra DOM.
        return (
          <button
            type="button"
            aria-label={`${ariaLabel}: ${tooltipLabel}`}
            aria-expanded={open}
            title={tooltipLabel}
            className={cn(
              'inline-flex h-7 w-7 items-center justify-center rounded-md',
              'text-muted-foreground transition-colors',
              'hover:bg-accent hover:text-foreground',
              'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
              className,
            )}
          >
            {country ? (
              <Flag
                countryCode={country}
                // Subtle hairline so flags with light edges (Japan,
                // Switzerland, …) don't blend into the header bg.
                className="h-4 w-5 overflow-hidden rounded-[2px] border border-border/60 ring-1 ring-black/5"
              />
            ) : hideFallbackIcon ? null : (
              <Globe className="h-3.5 w-3.5" aria-hidden />
            )}
          </button>
        );
      }}
    />
  );
}
