/**
 * Multi Select Field Component
 *
 * Renders a popover combobox with chip badges for multi-value selection.
 * Supports both static options and dynamically loaded options from an API.
 * Supports optional description, icon, disabled state, and grouping.
 */

import { useMemo, memo } from 'react';
import { Check, ChevronsUpDown, Loader2, X } from 'lucide-react';
import { Label } from '../ui/label';
import { Badge } from '../ui/badge';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '../ui/command';
import { ActionField, ActionFieldOption } from '../../types/action';
import { cn } from '../../lib/utils';
import { resolveIcon } from '../../lib/icon-resolver';

interface MultiSelectFieldProps {
  fieldName: string;
  field: ActionField;
  value: string[];
  onChange: (value: string[]) => void;
  error?: string;
  // Dynamic mode props (optional)
  options?: ActionFieldOption[];
  isLoading?: boolean;
  fieldError?: string;
  dependencyMet?: boolean;
  dependencyLabel?: string;
}

/**
 * Formats a string value into a readable label.
 */
function formatLabel(value: string): string {
  return value.charAt(0).toUpperCase() + value.slice(1).replace(/_/g, ' ');
}

/** Group options by their group property. Ungrouped options use '' as key. */
function groupOptions(options: ActionFieldOption[]): Map<string, ActionFieldOption[]> {
  const groups = new Map<string, ActionFieldOption[]>();
  for (const option of options) {
    const key = option.group ?? '';
    const list = groups.get(key);
    if (list) {
      list.push(option);
    } else {
      groups.set(key, [option]);
    }
  }
  return groups;
}

function OptionContent({ option }: { option: ActionFieldOption }) {
  const Icon = resolveIcon(option.icon);

  return (
    <div className="flex flex-col gap-0.5">
      <span className="flex items-center gap-1.5">
        {Icon && <Icon className="h-3.5 w-3.5 shrink-0 text-slate-500" />}
        {option.label}
      </span>
      {option.description && (
        <span className="text-[11px] text-slate-400 leading-tight">{option.description}</span>
      )}
    </div>
  );
}

export const MultiSelectField = memo(function MultiSelectField({
  fieldName,
  field,
  value,
  onChange,
  error,
  options: dynamicOptions,
  isLoading,
  fieldError,
  dependencyMet = true,
  dependencyLabel,
}: MultiSelectFieldProps) {
  // Normalize options - use dynamic options if provided, otherwise normalize from field.options
  const normalizedOptions = useMemo((): ActionFieldOption[] => {
    if (dynamicOptions) return dynamicOptions;
    if (!field.options) return [];

    if (Array.isArray(field.options)) {
      return field.options.map((opt) => {
        if (typeof opt === 'string') {
          return { value: opt, label: formatLabel(opt) };
        }
        return opt;
      });
    }

    return Object.entries(field.options).map(([key, label]) => ({
      value: key,
      label: String(label),
    }));
  }, [field.options, dynamicOptions]);

  const toggleValue = (optionValue: string) => {
    // Don't allow selecting disabled options
    const opt = normalizedOptions.find((o) => o.value === optionValue);
    if (opt?.disabled) return;

    if (value.includes(optionValue)) {
      onChange(value.filter((v) => v !== optionValue));
    } else {
      onChange([...value, optionValue]);
    }
  };

  const removeValue = (optionValue: string) => {
    onChange(value.filter((v) => v !== optionValue));
  };

  const getLabelForValue = (val: string): string => {
    return normalizedOptions.find((opt) => opt.value === val)?.label || val;
  };

  const hasGroups = normalizedOptions.some((opt) => opt.group);
  const grouped = useMemo(
    () => (hasGroups ? groupOptions(normalizedOptions) : null),
    [normalizedOptions, hasGroups],
  );

  // Show dependency message
  if (!dependencyMet) {
    return (
      <div className="space-y-2">
        <Label htmlFor={fieldName} className="text-[13px] font-medium text-slate-700 tracking-tight">
          {field.label}
          {field.required && <span className="text-rose-500 ml-0.5">*</span>}
        </Label>
        <div className="flex items-center gap-2 h-10 px-3 rounded-lg border border-slate-200 bg-slate-50/50">
          <span className="text-[13px] text-slate-400">
            Select {dependencyLabel || field.depends_on?.replace('_', ' ')} first.
          </span>
        </div>
        <p className="text-[12px] text-slate-400 leading-relaxed">{field.description}</p>
      </div>
    );
  }

  // Show loading state
  if (isLoading) {
    return (
      <div className="space-y-2">
        <Label htmlFor={fieldName} className="text-[13px] font-medium text-slate-700 tracking-tight">
          {field.label}
          {field.required && <span className="text-rose-500 ml-0.5">*</span>}
        </Label>
        <div className="flex items-center gap-2.5 h-10 px-3 rounded-lg border border-slate-200 bg-slate-50/50">
          <Loader2 className="w-4 h-4 animate-spin text-slate-400" />
          <span className="text-[13px] text-slate-400">Loading options...</span>
        </div>
        <p className="text-[12px] text-slate-400 leading-relaxed">{field.description}</p>
      </div>
    );
  }

  // Show field error
  if (fieldError) {
    return (
      <div className="space-y-2">
        <Label htmlFor={fieldName} className="text-[13px] font-medium text-slate-700 tracking-tight">
          {field.label}
          {field.required && <span className="text-rose-500 ml-0.5">*</span>}
        </Label>
        <div className="flex items-start gap-2 rounded-lg bg-rose-50 border border-rose-100 px-3 py-2.5">
          <span className="text-[13px] text-rose-700 leading-snug">{fieldError}</span>
        </div>
        <p className="text-[12px] text-slate-400 leading-relaxed">{field.description}</p>
      </div>
    );
  }

  const renderOptionItems = (options: ActionFieldOption[]) =>
    options.map((option) => {
      const isSelected = value.includes(option.value);
      return (
        <CommandItem
          key={option.value}
          value={option.label}
          onSelect={() => toggleValue(option.value)}
          className={cn('text-[13px]', option.disabled && 'opacity-50 cursor-not-allowed')}
          disabled={option.disabled}
        >
          <Check className={cn('mr-2 h-4 w-4', isSelected ? 'opacity-100' : 'opacity-0')} />
          <OptionContent option={option} />
        </CommandItem>
      );
    });

  return (
    <div className="space-y-2">
      <Label htmlFor={fieldName} className="text-[13px] font-medium text-slate-700 tracking-tight">
        {field.label}
        {field.required && <span className="text-rose-500 ml-0.5">*</span>}
      </Label>

      <Popover>
        <PopoverTrigger asChild>
          <button
            type="button"
            role="combobox"
            className={cn(
              'flex w-full min-h-[40px] items-center justify-between rounded-lg border border-slate-200 bg-white px-3 py-2 text-[13px]',
              'hover:border-slate-300 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 focus:border-cyan-500',
              'transition-colors duration-150',
            )}
          >
            <div className="flex flex-wrap gap-1.5 flex-1">
              {value.length === 0 ? (
                <span className="text-slate-400">
                  Select {field.label?.toLowerCase() || 'options'}...
                </span>
              ) : (
                value.map((val) => (
                  <Badge
                    key={val}
                    variant="secondary"
                    className="gap-1 px-2 py-0.5 text-[12px] bg-slate-100 hover:bg-slate-200 text-slate-700"
                  >
                    {getLabelForValue(val)}
                    <button
                      type="button"
                      className="ml-0.5 rounded-full outline-none hover:bg-slate-300 p-0.5"
                      onClick={(e) => {
                        e.stopPropagation();
                        removeValue(val);
                      }}
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ))
              )}
            </div>
            <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
          </button>
        </PopoverTrigger>
        <PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0" align="start">
          <Command>
            <CommandInput placeholder={`Search ${field.label?.toLowerCase() || 'options'}...`} />
            <CommandList>
              <CommandEmpty>No options found.</CommandEmpty>
              {grouped
                ? Array.from(grouped.entries()).map(([groupName, groupOpts]) => (
                    <CommandGroup key={groupName} heading={groupName || undefined}>
                      {renderOptionItems(groupOpts)}
                    </CommandGroup>
                  ))
                : (
                    <CommandGroup>
                      {renderOptionItems(normalizedOptions)}
                    </CommandGroup>
                  )}
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>

      <p className="text-[12px] text-slate-400 leading-relaxed">{field.description}</p>
      {error && (
        <div className="flex items-start gap-2 rounded-lg bg-rose-50 border border-rose-100 px-3 py-2.5">
          <span className="text-[13px] text-rose-700 leading-snug">{error}</span>
        </div>
      )}
    </div>
  );
});
