import * as React from 'react';
import { clsx } from 'clsx';
import { X } from 'lucide-react';

export interface TagInputProps {
  /** Controlled list of tags. */
  value: string[];
  /** Called whenever the tag list changes (add/remove/clear). */
  onChange: (next: string[]) => void;
  /** Placeholder shown when no tags are present. */
  placeholder?: string;
  /** Maximum number of tags allowed. */
  max?: number;
  /**
   * Normaliser — runs over every candidate before insertion. Default trims
   * whitespace and lowercases. Return an empty string to silently reject.
   */
  normalize?: (raw: string) => string;
  /** Validator — return `false` to silently reject the candidate. */
  validate?: (candidate: string, existing: string[]) => boolean;
  /** Disable input + chip removal. */
  disabled?: boolean;
  /**
   * Commit the in-progress buffer as a tag when the input loses focus.
   * Default `false` — committing on blur surprises users who click away
   * intending to discard the buffer (ROADMAP V4 IMP-3). Opt in explicitly.
   */
  commitOnBlur?: boolean;
  /** Accessible label for the editor. */
  ariaLabel?: string;
  className?: string;
}

const DEFAULT_NORMALIZE = (raw: string) => raw.trim().toLowerCase();
const DEFAULT_VALIDATE = (candidate: string, existing: string[]) =>
  candidate.length > 0 && !existing.includes(candidate);

/**
 * `<TagInput>` — chip-based multi-value editor.
 *
 *  - **Enter** or **,** commits the buffer as a new tag.
 *  - **Backspace** at start of empty buffer removes the last chip.
 *  - **Escape** clears the buffer.
 *
 * Replaces the bespoke tag editors found in notes/fastgap/voice/jarvisjr
 * (roadmap §2.2). Pure controlled component — no internal state besides
 * the in-progress buffer.
 */
export function TagInput({
  value,
  onChange,
  placeholder = 'Add a tag…',
  max,
  normalize = DEFAULT_NORMALIZE,
  validate = DEFAULT_VALIDATE,
  disabled = false,
  commitOnBlur = false,
  ariaLabel,
  className,
}: TagInputProps) {
  const [buffer, setBuffer] = React.useState('');
  const inputRef = React.useRef<HTMLInputElement>(null);

  const atCap = max !== undefined && value.length >= max;

  const commit = () => {
    if (atCap) return;
    const next = normalize(buffer);
    if (!validate(next, value)) {
      setBuffer('');
      return;
    }
    onChange([...value, next]);
    setBuffer('');
  };

  const remove = (idx: number) => {
    onChange(value.filter((_, i) => i !== idx));
  };

  const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (disabled) return;
    if (e.key === 'Enter' || e.key === ',') {
      e.preventDefault();
      commit();
      return;
    }
    if (e.key === 'Escape') {
      setBuffer('');
      return;
    }
    if (e.key === 'Backspace' && buffer.length === 0 && value.length > 0) {
      e.preventDefault();
      remove(value.length - 1);
    }
  };

  return (
    <div
      data-testid="bl-tag-input"
      role="group"
      aria-label={ariaLabel ?? 'Tags'}
      onClick={() => inputRef.current?.focus()}
      className={clsx(
        'flex min-h-10 flex-wrap items-center gap-1.5 rounded-lg border bg-[var(--bl-surface-card,#fff)] px-2 py-1.5 transition',
        'border-[var(--bl-border,rgba(0,0,0,0.12))]',
        'focus-within:border-[var(--bl-accent,#6366f1)] focus-within:ring-2 focus-within:ring-[var(--bl-accent-muted,rgba(99,102,241,0.18))]',
        disabled && 'cursor-not-allowed opacity-60',
        className,
      )}
    >
      {value.map((tag, i) => (
        <span
          key={`${tag}-${i}`}
          data-testid={`bl-tag-${i}`}
          className="inline-flex items-center gap-1 rounded-full bg-[var(--bl-accent-muted,rgba(99,102,241,0.16))] px-2 py-0.5 text-xs font-medium text-[var(--bl-accent,#6366f1)]"
        >
          {tag}
          {!disabled && (
            <button
              type="button"
              aria-label={`Remove ${tag}`}
              onClick={(e) => {
                e.stopPropagation();
                remove(i);
              }}
              className="rounded-full p-0.5 transition hover:bg-[var(--bl-accent,#6366f1)]/15"
            >
              <X className="h-3 w-3" aria-hidden="true" />
            </button>
          )}
        </span>
      ))}
      <input
        ref={inputRef}
        type="text"
        value={buffer}
        onChange={(e) => setBuffer(e.target.value)}
        onKeyDown={onKeyDown}
        onBlur={() => commitOnBlur && buffer.length > 0 && commit()}
        placeholder={value.length === 0 ? placeholder : ''}
        disabled={disabled || atCap}
        aria-label={ariaLabel ?? 'Add a tag'}
        className="min-w-[8ch] flex-1 bg-transparent px-1 py-0.5 text-sm outline-none placeholder:text-[var(--bl-text-tertiary,#999)]"
      />
      {atCap && (
        <span className="ml-auto text-[10px] font-mono uppercase text-[var(--bl-text-tertiary,#999)]">
          max {max}
        </span>
      )}
    </div>
  );
}

TagInput.displayName = 'TagInput';
