import { useRef, useEffect, useState, useMemo, useCallback } from "react";
import { Plus, X, Upload, Loader2, Link, ImageIcon, AlertCircle, Bold, Italic, List, Heading2, Pencil } from "lucide-react";
import { formatMarkup } from "@/lib/markup";
import { adminFetch } from "@/lib/csrf";
import type { RichListItem } from "@/types/content";

interface InputFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  type?: "text" | "url" | "tel";
}

const baseInput = "w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white placeholder-neutral-500 outline-none hover:border-gold/30 focus:border-gold transition-colors";
const textAreaInput = `${baseInput} resize-none overflow-hidden`;
const smallInput = "rounded-md border border-white/10 bg-neutral-800 px-2.5 py-1.5 text-sm text-white placeholder-neutral-600 outline-none hover:border-gold/30 focus:border-gold transition-colors";
const dashedInput = "flex-1 rounded-lg border border-dashed border-white/10 bg-neutral-800/50 px-4 py-2 text-sm text-white placeholder-neutral-600 outline-none hover:border-gold/30 hover:placeholder-neutral-500 focus:border-gold/50 transition-colors";
const inputCls = baseInput;

export function InputField({
  label,
  value,
  onChange,
  placeholder,
  type = "text",
}: InputFieldProps) {
  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <input
        type={type}
        value={value ?? ""}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        className={inputCls}
      />
    </div>
  );
}

export function ParticipantLimits({
  min,
  max,
  onMinChange,
  onMaxChange,
}: {
  min: number;
  max: number;
  onMinChange: (v: number) => void;
  onMaxChange: (v: number) => void;
}) {
  const [minStr, setMinStr] = useState(String(min));
  const [maxStr, setMaxStr] = useState(String(max));
  const minLocal = parseInt(minStr) || 0;
  const maxLocal = parseInt(maxStr) || 0;
  const minEmpty = minStr === "";
  const maxEmpty = maxStr === "";
  const maxError = (maxLocal > 0 && minLocal > 0 && maxLocal < minLocal) || minEmpty || maxEmpty;

  function handleMin(raw: string) {
    setMinStr(raw);
    if (raw === "") return;
    const v = parseInt(raw) || 0;
    const curMax = parseInt(maxStr) || 0;
    if (curMax > 0 && v > curMax) return;
    onMinChange(v);
  }

  function handleMax(raw: string) {
    setMaxStr(raw);
    if (raw === "") return;
    const v = parseInt(raw) || 0;
    const curMin = parseInt(minStr) || 0;
    if (v > 0 && v < curMin) return;
    onMaxChange(v);
  }

  const errorMsg = minEmpty || maxEmpty
    ? "Поле не может быть пустым"
    : maxLocal > 0 && minLocal > maxLocal
      ? "Макс. не может быть меньше мин."
      : null;

  return (
    <div className="grid grid-cols-2 gap-3">
      <div>
        <label className="block text-sm text-neutral-400 mb-1.5">Мин. участников</label>
        <input type="number" min={0} value={minStr} onChange={(e) => handleMin(e.target.value)}
          aria-describedby="min-hint"
          aria-invalid={minEmpty || undefined}
          className={`${inputCls} ${minEmpty ? "!border-red-500/50" : ""}`} />
        <p id="min-hint" className={`text-xs mt-1 ${minEmpty ? "text-red-400" : "text-neutral-600"}`}>
          {minEmpty ? "Поле не может быть пустым" : "Если записей меньше — занятие можно отменить"}
        </p>
      </div>
      <div>
        <label className="block text-sm text-neutral-400 mb-1.5">Макс. участников</label>
        <input type="number" min={0} value={maxStr} onChange={(e) => handleMax(e.target.value)}
          aria-describedby="max-hint"
          aria-invalid={(maxEmpty || (maxLocal > 0 && minLocal > maxLocal)) || undefined}
          className={`${inputCls} ${maxEmpty || (maxLocal > 0 && minLocal > maxLocal) ? "!border-red-500/50" : ""}`} />
        <p id="max-hint" className={`text-xs mt-1 ${errorMsg && !minEmpty ? "text-red-400" : "text-neutral-600"}`}>
          {maxEmpty ? "Поле не может быть пустым" : maxLocal > 0 && minLocal > maxLocal ? "Макс. не может быть меньше мин." : "0 = без лимита. При заполнении — лист ожидания"}
        </p>
      </div>
    </div>
  );
}

interface TextareaFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  rows?: number;
}

export function TextareaField({
  label,
  value,
  onChange,
  placeholder,
  rows = 3,
}: TextareaFieldProps) {
  const ref = useRef<HTMLTextAreaElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.style.height = "auto";
    el.style.height = el.scrollHeight + "px";
  }, [value]);

  useEffect(() => {
    function onResize() {
      const el = ref.current;
      if (!el) return;
      el.style.height = "auto";
      el.style.height = el.scrollHeight + "px";
    }
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <textarea
        ref={ref}
        value={value ?? ""}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        rows={rows}
        className={textAreaInput}
      />
    </div>
  );
}

interface RichTextareaProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  rows?: number;
}

export function RichTextarea({
  label,
  value,
  onChange,
  placeholder,
  rows = 4,
}: RichTextareaProps) {
  const ref = useRef<HTMLTextAreaElement>(null);
  const [editing, setEditing] = useState(false);
  const hasContent = Boolean(value?.trim());

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.style.height = "auto";
    el.style.height = el.scrollHeight + "px";
  }, [value]);

  useEffect(() => {
    function onResize() {
      const el = ref.current;
      if (!el) return;
      el.style.height = "auto";
      el.style.height = el.scrollHeight + "px";
    }
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  const wrapSelection = useCallback((before: string, after: string) => {
    const el = ref.current;
    if (!el) return;
    const start = el.selectionStart;
    const end = el.selectionEnd;
    const text = value ?? "";
    const selected = text.slice(start, end);

    // If already wrapped, unwrap
    const beforeCheck = text.slice(Math.max(0, start - before.length), start);
    const afterCheck = text.slice(end, end + after.length);
    if (beforeCheck === before && afterCheck === after) {
      const newText = text.slice(0, start - before.length) + selected + text.slice(end + after.length);
      onChange(newText);
      requestAnimationFrame(() => {
        el.selectionStart = start - before.length;
        el.selectionEnd = end - before.length;
        el.focus();
      });
      return;
    }

    const newText = text.slice(0, start) + before + selected + after + text.slice(end);
    onChange(newText);
    requestAnimationFrame(() => {
      if (selected) {
        el.selectionStart = start + before.length;
        el.selectionEnd = end + before.length;
      } else {
        el.selectionStart = start + before.length;
        el.selectionEnd = start + before.length;
      }
      el.focus();
    });
  }, [value, onChange]);

  const insertAtCursor = useCallback((text: string) => {
    const el = ref.current;
    if (!el) return;
    const start = el.selectionStart;
    const current = value ?? "";
    // Add newline before if not at start of line
    const lineStart = current.lastIndexOf("\n", start - 1) + 1;
    const prefix = start > lineStart ? "\n" : "";
    const newText = current.slice(0, start) + prefix + text + current.slice(start);
    onChange(newText);
    const cursorPos = start + prefix.length + text.length;
    requestAnimationFrame(() => {
      el.selectionStart = cursorPos;
      el.selectionEnd = cursorPos;
      el.focus();
    });
  }, [value, onChange]);

  // Track active formatting at cursor position
  const [cursorPos, setCursorPos] = useState<{ start: number; end: number }>({ start: 0, end: 0 });

  const updateCursorPos = useCallback(() => {
    const el = ref.current;
    if (!el) return;
    setCursorPos({ start: el.selectionStart, end: el.selectionEnd });
  }, []);

  const isBold = useMemo(() => {
    const text = value ?? "";
    const { start, end } = cursorPos;
    if (start !== end) {
      // Check if selection is wrapped in **
      return text.slice(Math.max(0, start - 2), start) === "**" && text.slice(end, end + 2) === "**";
    }
    // Check if cursor is inside **...**
    const before = text.slice(0, start);
    const after = text.slice(start);
    const lastOpen = before.lastIndexOf("**");
    if (lastOpen === -1) return false;
    const betweenOpen = before.slice(lastOpen + 2);
    if (betweenOpen.includes("**")) return false;
    return after.indexOf("**") !== -1;
  }, [value, cursorPos]);

  const isItalic = useMemo(() => {
    const text = value ?? "";
    const { start, end } = cursorPos;
    if (start !== end) {
      const cb = text[start - 1];
      const ca = text[end];
      return cb === "*" && ca === "*" && text[start - 2] !== "*" && text[end + 1] !== "*";
    }
    const before = text.slice(0, start);
    const after = text.slice(start);
    // Find single * (not **) before cursor
    const lastStar = before.lastIndexOf("*");
    if (lastStar === -1) return false;
    if (lastStar > 0 && before[lastStar - 1] === "*") return false;
    const nextStar = after.indexOf("*");
    if (nextStar === -1) return false;
    if (after[nextStar + 1] === "*") return false;
    return true;
  }, [value, cursorPos]);

  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
    // Use e.code for layout-independent shortcuts (works with Russian layout)
    if ((e.ctrlKey || e.metaKey) && e.code === "KeyB") {
      e.preventDefault();
      wrapSelection("**", "**");
    }
    if ((e.ctrlKey || e.metaKey) && e.code === "KeyI") {
      e.preventDefault();
      wrapSelection("*", "*");
    }
  }, [wrapSelection]);

  const toolbarBtn = (active: boolean) =>
    `rounded p-1.5 transition-colors ${
      active
        ? "text-gold bg-gold/15"
        : "text-neutral-500 hover:text-white hover:bg-white/10"
    }`;

  // Preview mode: show rendered markup
  if (!editing && hasContent) {
    return (
      <div>
        <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
        <div
          onClick={() => {
            setEditing(true);
            requestAnimationFrame(() => ref.current?.focus());
          }}
          className="group rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 cursor-text hover:border-gold/30 transition-colors relative"
        >
          <div className="text-sm leading-relaxed text-neutral-300">
            {formatMarkup(value)}
          </div>
          <div className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity">
            <span className="flex items-center gap-1 text-xs text-neutral-500">
              <Pencil size={10} />
              редактировать
            </span>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <div className="rounded-lg border border-white/10 bg-neutral-800 overflow-hidden hover:border-gold/30 focus-within:border-gold transition-colors">
        {/* Toolbar */}
        <div className="flex items-center gap-0.5 px-2 py-1 border-b border-white/5">
          <button
            type="button"
            onMouseDown={(e) => e.preventDefault()}
            onClick={() => wrapSelection("**", "**")}
            className={toolbarBtn(isBold)}
            title="Жирный (Ctrl+B)"
          >
            <Bold size={14} />
          </button>
          <button
            type="button"
            onMouseDown={(e) => e.preventDefault()}
            onClick={() => wrapSelection("*", "*")}
            className={toolbarBtn(isItalic)}
            title="Курсив (Ctrl+I)"
          >
            <Italic size={14} />
          </button>
          <div className="w-px h-4 bg-white/10 mx-1" />
          <button
            type="button"
            onMouseDown={(e) => e.preventDefault()}
            onClick={() => insertAtCursor("🤍 ")}
            className={toolbarBtn(false)}
            title="Пункт списка"
          >
            <List size={14} />
          </button>
          <button
            type="button"
            onMouseDown={(e) => e.preventDefault()}
            onClick={() => wrapSelection("## ", "")}
            className={toolbarBtn(false)}
            title="Подзаголовок"
          >
            <Heading2 size={14} />
          </button>
        </div>
        {/* Textarea */}
        <textarea
          ref={ref}
          value={value ?? ""}
          onChange={(e) => onChange(e.target.value)}
          onKeyDown={handleKeyDown}
          onKeyUp={updateCursorPos}
          onClick={updateCursorPos}
          onSelect={updateCursorPos}
          onBlur={() => setEditing(false)}
          placeholder={placeholder}
          rows={rows}
          className="w-full bg-transparent px-4 py-2.5 text-white placeholder-neutral-500 outline-none resize-none"
        />
      </div>
    </div>
  );
}

interface SelectFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  options: { value: string; label: string }[];
  placeholder?: string;
  hint?: string;
}

export function SelectField({
  label,
  value,
  onChange,
  options,
  placeholder,
  hint,
}: SelectFieldProps) {
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState("");
  const [highlightIndex, setHighlightIndex] = useState(-1);
  const containerRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const selectedLabel = options.find((o) => o.value === value)?.label || "";
  const filtered = search
    ? options.filter((o) => {
        const q = search.toLowerCase();
        return o.label.toLowerCase().split(/\s+/).some((word) => word.startsWith(q));
      })
    : options;

  const showSearch = options.length > 3;

  function handleKeyDown(e: React.KeyboardEvent) {
    if (e.key === "Escape") {
      setOpen(false);
      setSearch("");
      return;
    }
    if (e.key === "ArrowDown") {
      e.preventDefault();
      if (!open) { setOpen(true); setHighlightIndex(0); return; }
      setHighlightIndex((prev) => (prev + 1) % filtered.length);
    }
    if (e.key === "ArrowUp") {
      e.preventDefault();
      if (!open) { setOpen(true); setHighlightIndex(filtered.length - 1); return; }
      setHighlightIndex((prev) => (prev - 1 + filtered.length) % filtered.length);
    }
    if (e.key === "Enter" && open && highlightIndex >= 0 && highlightIndex < filtered.length) {
      e.preventDefault();
      onChange(filtered[highlightIndex].value);
      setOpen(false);
      setSearch("");
      setHighlightIndex(-1);
    }
  }

  useEffect(() => {
    if (!open) return;
    function handle(e: MouseEvent) {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false);
        setSearch("");
      }
    }
    document.addEventListener("mousedown", handle);
    return () => document.removeEventListener("mousedown", handle);
  }, [open]);

  return (
    <div ref={containerRef} className="relative">
      {label && (
        <label className="flex items-center gap-1.5 text-sm text-neutral-400 mb-1.5">
          {label}
          {hint && (
            <span className="group relative">
              <span className="flex h-4 w-4 items-center justify-center rounded-full border border-white/15 text-[10px] text-neutral-500 hover:text-white hover:border-white/30 transition-colors cursor-help">?</span>
              <span className="absolute left-6 top-1/2 -translate-y-1/2 z-50 w-52 rounded-lg border border-white/10 bg-neutral-800 px-3 py-2 text-[11px] leading-relaxed text-neutral-300 shadow-xl opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-opacity">
                {hint}
              </span>
            </span>
          )}
        </label>
      )}
      {showSearch ? (
        <input
          ref={inputRef}
          type="text"
          value={open ? search : selectedLabel}
          onChange={(e) => { setSearch(e.target.value); if (!open) setOpen(true); setHighlightIndex(0); }}
          onFocus={() => { setOpen(true); setSearch(""); }}
          onKeyDown={handleKeyDown}
          role="combobox"
          aria-expanded={open}
          aria-haspopup="listbox"
          placeholder={placeholder || "Выберите..."}
          className={`w-full rounded-lg border bg-neutral-800 outline-none transition-colors ${
            label ? "px-4 py-2.5" : "px-2 py-1 text-xs"
          } ${open ? "border-gold" : "border-white/10"} ${!open && value ? "text-white" : "text-white"} placeholder-neutral-500`}
        />
      ) : (
        <button
          type="button"
          onClick={() => setOpen(!open)}
          onKeyDown={handleKeyDown}
          aria-expanded={open}
          aria-haspopup="listbox"
          className={`w-full rounded-lg border bg-neutral-800 text-left outline-none transition-colors ${
            label ? "px-4 py-2.5" : "px-2 py-1 text-xs"
          } ${open ? "border-gold" : "border-white/10"} ${value ? "text-white" : "text-neutral-500"}`}
        >
          {selectedLabel || placeholder || "Выберите..."}
        </button>
      )}

      {open && (
        <div role="listbox" className="absolute z-50 mt-1 w-full rounded-lg border border-white/10 bg-neutral-800 shadow-xl overflow-hidden">
          <div className="max-h-48 overflow-y-auto">
            {filtered.length === 0 && (
              <div className="px-4 py-2 text-sm text-neutral-500">Ничего не найдено</div>
            )}
            {filtered.map((opt, idx) => (
              <button
                key={opt.value || `opt-${idx}`}
                type="button"
                role="option"
                aria-selected={opt.value === value}
                onMouseDown={(e) => e.preventDefault()}
                onMouseEnter={() => setHighlightIndex(idx)}
                onClick={() => {
                  onChange(opt.value);
                  setOpen(false);
                  setSearch("");
                  setHighlightIndex(-1);
                  inputRef.current?.blur();
                }}
                className={`w-full px-4 py-2 text-left text-sm transition-colors ${
                  idx === highlightIndex ? "bg-white/10" : "hover:bg-white/5"
                } ${opt.value === value ? "text-gold bg-gold/5" : "text-white"}`}
              >
                {opt.label}
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

interface TimeRangeFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  onBlur?: () => void;
}

export function TimeRangeField({ label, value, onChange, onBlur }: TimeRangeFieldProps) {
  const parts = value.split("–");
  const start = parts[0]?.trim() || "";
  const end = parts[1]?.trim() || "";

  function update(s: string, e: string) {
    if (s && e) {
      onChange(`${s}–${e}`);
    } else if (s) {
      onChange(s);
    } else {
      onChange("");
    }
  }

  function handleStartChange(newStart: string) {
    if (newStart && end && newStart >= end) {
      update(newStart, "");
    } else {
      update(newStart, end);
    }
  }

  function handleEndChange(newEnd: string) {
    if (start && newEnd && newEnd <= start) return;
    update(start, newEnd);
  }

  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <div className="flex items-center gap-2">
        <input
          type="time"
          value={start}
          onChange={(e) => handleStartChange(e.target.value)}
          onBlur={onBlur}
          className="flex-1 rounded-lg border border-white/10 bg-neutral-800 px-3 py-2.5 text-white outline-none focus:border-gold transition-colors"
        />
        <span className="text-neutral-500">–</span>
        <input
          type="time"
          value={end}
          onChange={(e) => handleEndChange(e.target.value)}
          onBlur={onBlur}
          className="flex-1 rounded-lg border border-white/10 bg-neutral-800 px-3 py-2.5 text-white outline-none focus:border-gold transition-colors"
        />
      </div>
    </div>
  );
}

interface ToggleFieldProps {
  label: string;
  checked: boolean;
  onChange: (checked: boolean) => void;
}

export function ToggleField({ label, checked, onChange }: ToggleFieldProps) {
  return (
    <label className="flex items-center gap-2 cursor-pointer">
      <button
        type="button"
        role="switch"
        aria-checked={checked}
        onClick={() => onChange(!checked)}
        className={`relative h-6 w-11 rounded-full transition-colors ${
          checked ? "bg-gold" : "bg-neutral-700"
        }`}
      >
        <span
          className={`absolute top-0.5 left-0.5 h-5 w-5 rounded-full bg-white transition-transform ${
            checked ? "translate-x-5" : ""
          }`}
        />
      </button>
      <span className="text-sm text-neutral-300">{label}</span>
    </label>
  );
}

interface ListFieldProps {
  label: string;
  items: string[];
  onChange: (items: string[]) => void;
  placeholder?: string;
}

export function ListField({ label, items, onChange, placeholder }: ListFieldProps) {
  const [draft, setDraft] = useState("");

  function add() {
    const val = draft.trim();
    if (!val) return;
    onChange([...items, val]);
    setDraft("");
  }

  function remove(index: number) {
    onChange(items.filter((_, i) => i !== index));
  }

  function update(index: number, value: string) {
    onChange(items.map((item, i) => (i === index ? value : item)));
  }

  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <div className="space-y-2">
        {items.map((item, i) => (
          <div key={i} className="flex items-center gap-2">
            <input
              type="text"
              value={item}
              onChange={(e) => update(i, e.target.value)}
              className="flex-1 rounded-lg border border-white/10 bg-neutral-800 px-4 py-2 text-sm text-white outline-none focus:border-gold transition-colors"
            />
            <button
              type="button"
              onClick={() => remove(i)}
              className="shrink-0 rounded-lg p-2 text-neutral-500 hover:text-red-400 transition-colors"
            >
              <X size={14} />
            </button>
          </div>
        ))}
        <div className="flex items-center gap-2">
          <input
            type="text"
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); add(); } }}
            onBlur={add}
            placeholder={placeholder || "Добавить..."}
            className={dashedInput}
          />
          <button
            type="button"
            onClick={add}
            disabled={!draft.trim()}
            className="shrink-0 rounded-lg p-2 text-neutral-500 hover:text-gold transition-colors disabled:opacity-30"
          >
            <Plus size={14} />
          </button>
        </div>
      </div>
    </div>
  );
}

interface VictoryListFieldProps {
  label: string;
  items: RichListItem[];
  onChange: (items: RichListItem[]) => void;
  placeholder?: string;
  onLinkValidate?: (key: string, error: string | null) => void;
  onUploadComplete?: () => void;
}

export function VictoryListField({ label, items, onChange, placeholder, onLinkValidate, onUploadComplete }: VictoryListFieldProps) {
  const [draft, setDraft] = useState("");
  const [uploadingIndex, setUploadingIndex] = useState<number | null>(null);

  function add() {
    const val = draft.trim();
    if (!val) return;
    onChange([...items, { text: val }]);
    setDraft("");
  }

  function remove(index: number) {
    onChange(items.filter((_, i) => i !== index));
  }

  function updateText(index: number, text: string) {
    onChange(items.map((item, i) => (i === index ? { ...item, text } : item)));
  }

  function updateLink(index: number, link: string) {
    onChange(items.map((item, i) => (i === index ? { ...item, link: link || undefined } : item)));
  }

  function removeImage(index: number) {
    onChange(items.map((item, i) => (i === index ? { ...item, image: undefined } : item)));
  }

  async function handleUpload(index: number, e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    setUploadingIndex(index);
    const formData = new FormData();
    formData.append("file", file);
    formData.append("folder", "team");
    try {
      const res = await adminFetch("/api/admin/upload", { method: "POST", body: formData });
      const result = await res.json();
      if (result.path) {
        onChange(items.map((item, i) => (i === index ? { ...item, image: result.path } : item)));
        onUploadComplete?.();
      }
    } catch { /* upload failed */ } finally {
      setUploadingIndex(null);
    }
  }

  return (
    <div>
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <div className="space-y-2">
        {items.map((item, i) => (
          <div key={i} className="rounded-lg border border-white/10 bg-neutral-800/50 p-2.5 space-y-1.5 transition-colors hover:border-gold/30 hover:bg-neutral-800/80 focus-within:border-gold/50 focus-within:bg-neutral-800">
            <div className="flex items-center gap-1.5">
              <input
                type="text"
                value={item.text}
                onChange={(e) => updateText(i, e.target.value)}
                className="flex-1 rounded-md border border-white/10 bg-neutral-800 px-2.5 py-1.5 text-sm text-white outline-none focus:border-gold transition-colors"
              />
              <button
                type="button"
                onClick={() => remove(i)}
                className="shrink-0 rounded-md p-1.5 text-neutral-500 hover:text-red-400 transition-colors"
              >
                <X size={14} />
              </button>
            </div>
            <div className="flex items-center gap-1.5">
              {item.image ? (
                <div className="flex items-center gap-1 rounded bg-neutral-700/50 px-1.5 py-0.5 text-[11px] text-neutral-300">
                  <ImageIcon size={10} className="text-gold" />
                  <span className="max-w-[80px] truncate">{item.image.split("/").pop()}</span>
                  <button type="button" onClick={() => removeImage(i)} className="text-neutral-500 hover:text-red-400">
                    <X size={9} />
                  </button>
                </div>
              ) : (
                <label className="flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 text-[11px] text-neutral-500 hover:text-neutral-300 transition-colors">
                  {uploadingIndex === i ? <Loader2 size={10} className="animate-spin" /> : <Upload size={10} />}
                  {uploadingIndex === i ? "..." : "Фото"}
                  <input type="file" accept="image/*" onChange={(e) => handleUpload(i, e)} className="hidden" />
                </label>
              )}
              <ValidatedLinkField
                value={item.link || ""}
                onChange={(v) => updateLink(i, v)}
                validationKey={`edu-${i}`}
                onValidate={onLinkValidate}
              />
            </div>
          </div>
        ))}
        <div className="flex items-center gap-2">
          <input
            type="text"
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); add(); } }}
            onBlur={add}
            placeholder={placeholder || "Добавить..."}
            className={dashedInput}
          />
          <button
            type="button"
            onClick={add}
            disabled={!draft.trim()}
            className="shrink-0 rounded-lg p-2 text-neutral-500 hover:text-gold transition-colors disabled:opacity-30"
          >
            <Plus size={14} />
          </button>
        </div>
      </div>
    </div>
  );
}

// --- Link Field with Validation ---
interface ValidatedLinkFieldProps {
  value: string;
  onChange: (value: string) => void;
  onValidate?: (key: string, error: string | null) => void;
  validationKey?: string;
  placeholder?: string;
}

export function ValidatedLinkField({ value, onChange, onValidate, validationKey, placeholder }: ValidatedLinkFieldProps) {
  const [error, setError] = useState<string | null>(null);

  function validate(url: string) {
    if (!url) {
      setError(null);
      onValidate?.(validationKey || "", null);
      return;
    }
    try {
      new URL(url);
      setError(null);
      onValidate?.(validationKey || "", null);
    } catch {
      setError("Некорректная ссылка");
      onValidate?.(validationKey || "", "invalid");
    }
  }

  return (
    <div className="flex items-center gap-1.5 flex-1">
      <Link size={12} className="text-neutral-500 shrink-0" />
      <div className="relative flex-1">
        <input
          type="text"
          value={value}
          onChange={(e) => {
            onChange(e.target.value);
            validate(e.target.value);
          }}
          placeholder={placeholder || "Ссылка..."}
          className={`w-full rounded-md border bg-neutral-800 px-2 py-1 text-xs text-white placeholder-neutral-600 outline-none transition-colors ${
            error ? "border-red-500/50" : "border-white/5 focus:border-gold/50"
          }`}
        />
        {error && (
          <span className="absolute right-1.5 top-1/2 -translate-y-1/2">
            <AlertCircle size={10} className="text-red-400" />
          </span>
        )}
      </div>
    </div>
  );
}

// --- Autocomplete Multi-Select ---
export function AutocompleteMulti({
  label,
  value,
  onChange,
  options,
  placeholder,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  options: string[];
  placeholder?: string;
}) {
  const selected = useMemo(() => (value ? value.split(/\s*[,·]\s*/).filter(Boolean) : []), [value]);
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const filtered = useMemo(() => {
    if (!query) return options.filter((o) => !selected.includes(o));
    const q = query.toLowerCase();
    return options.filter((o) => !selected.includes(o) && o.toLowerCase().includes(q));
  }, [query, options, selected]);

  useEffect(() => {
    if (!open) return;
    function handle(e: MouseEvent) {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false);
        setQuery("");
      }
    }
    document.addEventListener("mousedown", handle);
    return () => document.removeEventListener("mousedown", handle);
  }, [open]);

  function addItem(item: string) {
    onChange([...selected, item].join(" · "));
    setQuery("");
    inputRef.current?.focus();
  }

  function removeItem(item: string) {
    onChange(selected.filter((s) => s !== item).join(" · "));
  }

  function handleKeyDown(e: React.KeyboardEvent) {
    if (e.key === "Enter") {
      e.preventDefault();
      if (filtered.length > 0) addItem(filtered[0]);
      else if (query.trim()) addItem(query.trim());
    }
    if (e.key === "Backspace" && !query && selected.length > 0) {
      removeItem(selected[selected.length - 1]);
    }
    if (e.key === "Escape") { setOpen(false); setQuery(""); }
  }

  return (
    <div ref={containerRef} className="relative">
      <label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
      <div
        onClick={() => { setOpen(true); inputRef.current?.focus(); }}
        className={`flex flex-wrap items-center gap-1.5 rounded-lg border bg-neutral-800 px-3 py-2 min-h-[42px] cursor-text transition-colors ${
          open ? "border-gold" : "border-white/10 hover:border-gold/30"
        }`}
      >
        {selected.map((item) => (
          <span key={item} className="inline-flex items-center gap-1 rounded-full bg-gold/15 border border-gold/30 px-2.5 py-0.5 text-xs font-medium text-gold">
            {item}
            <button type="button" onClick={(e) => { e.stopPropagation(); removeItem(item); }} className="text-gold/60 hover:text-gold transition-colors">
              <X size={10} />
            </button>
          </span>
        ))}
        <input
          ref={inputRef}
          type="text"
          value={query}
          onChange={(e) => { setQuery(e.target.value); setOpen(true); }}
          onFocus={() => setOpen(true)}
          onKeyDown={handleKeyDown}
          placeholder={selected.length === 0 ? placeholder : ""}
          className="flex-1 min-w-[80px] bg-transparent text-sm text-white placeholder-neutral-500 outline-none"
        />
      </div>
      {open && filtered.length > 0 && (
        <div className="absolute z-50 mt-1 w-full rounded-lg border border-white/10 bg-neutral-800 shadow-xl overflow-hidden max-h-48 overflow-y-auto">
          {filtered.map((opt) => (
            <button key={opt} type="button" onMouseDown={(e) => e.preventDefault()} onClick={() => addItem(opt)}
              className="w-full px-4 py-2 text-left text-sm text-white hover:bg-white/5 transition-colors">
              {opt}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}
