/**
 * Карточка создания ремонта (Фича 4 + У19/У20/У21/У24/У25/У42/У45).
 *
 * Online-only flow (PR-7). Offline-first из У47/PR-8 — следующий PR.
 *
 * Блоки:
 *  - Шапка: машина (snapshot из /cars/{id}/context) + механик + водитель.
 *  - Пробег (предзаполняется StarLine, можно перебить вручную).
 *  - Фото — multi-upload через presign + PUT в `tmp/`.
 *  - Работы — выбор из справочника, цена редактируема через
 *    «карандашик» (У19); комментарий обязателен при разблокировке.
 *  - Запчасти — текст + qty, автодополнение (У43).
 *  - Замена масла — раскрывающийся блок с дефолтным интервалом 10000 (У25).
 *
 * Сохранение: POST /repairs с `Idempotency-Key` (UUID v4 в state).
 */
import { useEffect, useMemo, useRef, useState } from "react";
import { useNavigate, useParams, useLocation } from "react-router-dom";
import { ChevronLeft, Plus, Trash2, Pencil, Camera } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { repairCanSubmit, repairSubmitWhyDisabled } from "@/lib/repairForm";
import WorksPickerModal from "@/components/repairs/WorksPickerModal";
import MechanicsField, { type SelectedMechanic } from "@/components/repairs/MechanicsField";
import { getMe } from "@/api/me";
import {
  createRepair,
  getCarContext,
  presignPhoto,
  searchWorks,
  suggestParts,
  uploadPhotoToTmp,
  type CarContext,
  type CreatePhotoPayload,
  type MechWork,
  type PresignResponse,
} from "@/api/repairsCreate";

// ── Local state types ─────────────────────────────────────────────────────

interface PhotoState {
  presign: PresignResponse;
  tag: "auto" | "part" | "other";
  status: "uploading" | "uploaded" | "error";
  errorMessage?: string;
  // Превью локального файла через URL.createObjectURL — отдаётся в <img>
  // вместо плейсхолдера «Загружено». Освобождается через revokeObjectURL
  // при удалении и при размонтировании страницы.
  previewUrl?: string;
}

interface WorkRow {
  // Идентификатор строки внутри UI (для key); тождественен work_catalog_id
  // + автоинкремент, чтобы дубли по У2 различались.
  rowKey: string;
  work_catalog_id: number;
  name: string; // снапшот имени из прайса
  price_catalog: number;
  // "" допустим в процессе редактирования — иначе React при очистке inputа
  // сразу подставляет "0" и его приходится курсором обходить, см. жалобу
  // механиков. На submit пустое трактуется как 0 (или как ошибка валидации).
  price_applied: number | "";
  unlocked: boolean; // карандашик разблокировал поле
  override_comment: string;
}

interface PartRow {
  rowKey: string;
  name: string;
  qty: number;
}

interface OilChangeState {
  enabled: boolean;
  next_in_km: number;
  sticker: PhotoState | null;
}


// Цены ремонта — целые рубли без копеек. API отдаёт Numeric(10,2)
// строкой типа "500.00" — пропускаем через округление при отображении.
function fmtPrice(p: number | string): string {
  const n = Number(p);
  if (Number.isNaN(n)) return String(p);
  return new Intl.NumberFormat("ru-RU", { maximumFractionDigits: 0 }).format(Math.round(n));
}

function uuid4(): string {
  // crypto.randomUUID требует secure context; mechanic.pptaxi.ru — https.
  return (crypto as any).randomUUID
    ? (crypto as any).randomUUID()
    : `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
}


export default function CreateRepairPage() {
  const navigate = useNavigate();
  const { carId: carIdRaw } = useParams<{ carId: string }>();
  const location = useLocation();
  const isExternal = !carIdRaw;
  const externalState = location.state as { plate: string; make: string | null } | null;
  const carId = carIdRaw ? Number(carIdRaw) : 0;

  // Idempotency-Key для этой формы — стабилен между ре-сабмитами (У20).
  const idemKey = useRef<string>(uuid4());

  const [ctx, setCtx] = useState<CarContext | null>(null);
  const [ctxError, setCtxError] = useState<string | null>(null);

  const [mileage, setMileage] = useState<number | null>(null);
  const [photos, setPhotos] = useState<PhotoState[]>([]);
  const [works, setWorks] = useState<WorkRow[]>([]);
  const [parts, setParts] = useState<PartRow[]>([]);
  // Работавшие механики (делёж 1/N). По умолчанию — текущий механик
  // (создатель), подтягивается из /me. Можно убрать/заменить.
  const [mechanics, setMechanics] = useState<SelectedMechanic[]>([]);
  const [oilChange, setOilChange] = useState<OilChangeState>({
    enabled: false,
    next_in_km: 10000,
    sticker: null,
  });

  const [worksPicker, setWorksPicker] = useState<{ open: boolean; q: string; results: MechWork[] }>(
    { open: false, q: "", results: [] },
  );

  const [submitting, setSubmitting] = useState(false);

  // Initial: подгрузить контекст машины.
  useEffect(() => {
    if (isExternal) {
      if (!externalState) {
        // Прямой заход/рефреш без данных — возвращаем к выбору машины.
        navigate("/repairs/new", { replace: true });
        return;
      }
      setCtx({
        id: 0,
        plate: externalState.plate,
        brand: externalState.make,
        model: null,
        mileage_starline: null,
        driver_id: null,
        driver_name: null,
      });
      setMileage(null);
      return;
    }
    if (!carId) return;
    getCarContext(carId)
      .then((c) => {
        setCtx(c);
        setMileage(c.mileage_starline);
      })
      .catch((e) => setCtxError((e as Error).message || "Не удалось загрузить машину"));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [carId, isExternal]);

  // Дефолтный механик-создатель: подтягиваем себя из /me. Если /me упал —
  // оставляем список пустым (backend всё равно засидит создателя на create).
  useEffect(() => {
    getMe()
      .then((me) => setMechanics([{ mechanic_id: me.id, name: me.name }]))
      .catch(() => {
        /* noop — список останется пустым, backend засидит создателя */
      });
  }, []);

  // У24 упрощено: пробег ввода в форме теперь один — главный «Пробег (км)»
  // в шапке. На submit подставляется и в oil_change.mileage_at_change, чтобы
  // не заставлять механика вводить одно и то же дважды.

  // ── Photo upload ─────────────────────────────────────────────────────────

  const onPhotoInput = async (files: FileList | null, target: "gallery" | "sticker") => {
    if (!files || files.length === 0) return;
    for (const file of Array.from(files)) {
      const ext = (file.name.split(".").pop() || "jpg").toLowerCase();
      const previewUrl = URL.createObjectURL(file);
      const placeholder: PhotoState = {
        presign: {
          photo_uuid: uuid4(),
          extension: ext,
          content_type: file.type || "image/jpeg",
          key: "",
          upload_url: "",
          expires_in: 0,
        },
        tag: "auto",
        status: "uploading",
        previewUrl,
      };
      if (target === "gallery") setPhotos((arr) => [...arr, placeholder]);
      else setOilChange((oc) => ({ ...oc, sticker: { ...placeholder, tag: "auto" } }));

      try {
        const presign = await presignPhoto(ext, placeholder.presign.photo_uuid);
        await uploadPhotoToTmp(file, presign);
        const updated: PhotoState = { presign, tag: "auto", status: "uploaded", previewUrl };
        if (target === "gallery") {
          setPhotos((arr) =>
            arr.map((p) => (p.presign.photo_uuid === presign.photo_uuid ? updated : p)),
          );
        } else {
          setOilChange((oc) => ({ ...oc, sticker: updated }));
        }
      } catch (e) {
        const msg = (e as Error).message || "Ошибка загрузки";
        if (target === "gallery") {
          setPhotos((arr) =>
            arr.map((p) =>
              p.presign.photo_uuid === placeholder.presign.photo_uuid
                ? { ...p, status: "error", errorMessage: msg }
                : p,
            ),
          );
        } else {
          setOilChange((oc) => ({
            ...oc,
            sticker: oc.sticker ? { ...oc.sticker, status: "error", errorMessage: msg } : oc.sticker,
          }));
        }
      }
    }
  };

  const removePhoto = (photoUuid: string) =>
    setPhotos((arr) => {
      const target = arr.find((p) => p.presign.photo_uuid === photoUuid);
      if (target?.previewUrl) URL.revokeObjectURL(target.previewUrl);
      return arr.filter((p) => p.presign.photo_uuid !== photoUuid);
    });

  // ── Works picker ─────────────────────────────────────────────────────────

  const openWorksPicker = async () => {
    setWorksPicker({ open: true, q: "", results: [] });
    const list = await searchWorks("");
    setWorksPicker((s) => ({ ...s, results: list }));
  };

  const queryWorks = async (q: string) => {
    setWorksPicker((s) => ({ ...s, q }));
    const list = await searchWorks(q);
    setWorksPicker((s) => ({ ...s, results: list }));
  };

  const addWorkFromCatalog = (w: MechWork) => {
    const price = Math.round(Number(w.price));
    setWorks((arr) => [
      ...arr,
      {
        rowKey: uuid4(),
        work_catalog_id: w.id,
        name: w.name,
        price_catalog: price,
        price_applied: price,
        unlocked: false,
        override_comment: "",
      },
    ]);
    setWorksPicker({ open: false, q: "", results: [] });
  };

  const toggleWorkUnlock = (rowKey: string) => {
    setWorks((arr) =>
      arr.map((w) =>
        w.rowKey === rowKey
          ? w.unlocked
            ? // повторный тап = отмена правки, возврат к цене прайса (У19)
              { ...w, unlocked: false, price_applied: w.price_catalog, override_comment: "" }
            : { ...w, unlocked: true }
          : w,
      ),
    );
  };

  const removeWork = (rowKey: string) =>
    setWorks((arr) => arr.filter((w) => w.rowKey !== rowKey));

  const totalSum = useMemo(
    () => works.reduce((acc, w) => acc + Number(w.price_applied || 0), 0),
    [works],
  );

  // ── Parts ────────────────────────────────────────────────────────────────

  const [partsDraft, setPartsDraft] = useState<{ name: string; suggestions: string[] }>({ name: "", suggestions: [] });

  const queryPartSuggestions = async (q: string) => {
    setPartsDraft({ name: q, suggestions: [] });
    if (!q.trim()) return;
    const list = await suggestParts(q);
    // У43 race-fix: пока запрос для "К" летел, юзер дописал до "Кепу" — поздний
    // ответ не должен перезаписывать .name старым значением (это и есть
    // «текст частично сам стирается»). Применяем suggestions только если
    // ввод не менялся; иначе тихо роняем ответ.
    setPartsDraft((prev) => {
      if (prev.name !== q) return prev;
      return { name: q, suggestions: list.map((s) => s.name) };
    });
  };

  const addPart = (name: string) => {
    const trimmed = name.trim();
    if (!trimmed) return;
    setParts((arr) => [...arr, { rowKey: uuid4(), name: trimmed, qty: 1 }]);
    setPartsDraft({ name: "", suggestions: [] });
  };

  const removePart = (rowKey: string) =>
    setParts((arr) => arr.filter((p) => p.rowKey !== rowKey));

  // ── Submit ───────────────────────────────────────────────────────────────

  const canSubmit = () => repairCanSubmit(photos, works);
  const submitWhyDisabled = (): string => repairSubmitWhyDisabled(photos, works);

  const onSubmit = async () => {
    const reason = submitWhyDisabled();
    if (reason) {
      toast.error(reason);
      return;
    }
    setSubmitting(true);
    try {
      const photoPayload: CreatePhotoPayload[] = photos.map((p, i) => ({
        photo_uuid: p.presign.photo_uuid,
        extension: p.presign.extension,
        tag: p.tag,
        sort_order: i,
      }));
      const result = await createRepair(
        {
          ...(isExternal
            ? { external_car: { plate: externalState!.plate, make: externalState!.make } }
            : { car_id: carId }),
          // Передаём список работавших механиков; если пуст — backend засидит
          // создателя сам (см. seed_creator_mechanic).
          ...(mechanics.length > 0
            ? { mechanic_ids: mechanics.map((m) => m.mechanic_id) }
            : {}),
          mileage,
          works: works.map((w) => ({
            work_catalog_id: w.work_catalog_id,
            price_applied: Number(w.price_applied),
            manual_override: w.unlocked,
            override_comment: w.unlocked ? w.override_comment.trim() : null,
          })),
          parts: parts.map((p) => ({ name: p.name, qty: p.qty })),
          photos: photoPayload,
          oil_change: oilChange.enabled
            ? {
                enabled: true,
                // Один источник истины — главный пробег ремонта (см. У24).
                mileage_at_change: mileage,
                next_in_km: oilChange.next_in_km,
                sticker_photo_uuid:
                  oilChange.sticker?.status === "uploaded"
                    ? oilChange.sticker.presign.photo_uuid
                    : null,
                sticker_extension:
                  oilChange.sticker?.status === "uploaded"
                    ? oilChange.sticker.presign.extension
                    : null,
              }
            : null,
        },
        idemKey.current,
      );
      toast.success(`Ремонт #${result.id} сохранён`);
      navigate("/repairs", { replace: true });
    } catch (e) {
      toast.error((e as Error).message || "Не удалось сохранить");
    } finally {
      setSubmitting(false);
    }
  };

  if (ctxError) {
    return (
      <div className="container max-w-2xl py-8">
        <div className="rounded-md border border-destructive bg-destructive/10 p-3 text-sm">
          {ctxError}
        </div>
      </div>
    );
  }
  if (!ctx) {
    return (
      <div className="container max-w-2xl py-8">
        <div className="text-sm text-muted-foreground">Загрузка…</div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-background flex flex-col">
      <header className="sticky top-0 z-10 bg-background/95 backdrop-blur border-b">
        <div className="flex items-center justify-between p-3">
          <Button variant="ghost" size="sm" onClick={() => navigate(-1)} className="-ml-2">
            <ChevronLeft className="h-5 w-5" />
            <span className="ml-1">Назад</span>
          </Button>
          <h1 className="text-base font-semibold">Новый ремонт</h1>
          <Button
            variant="default"
            size="sm"
            disabled={submitting || !canSubmit()}
            onClick={onSubmit}
            title={submitWhyDisabled() || undefined}
          >
            {submitting ? "Сохранение…" : "Сохранить"}
          </Button>
        </div>
        <div className="px-3 pb-3 text-sm">
          <div className="font-medium">{ctx.plate}</div>
          <div className="text-muted-foreground">
            {[ctx.brand, ctx.model].filter(Boolean).join(" ")}
            {isExternal
              ? " · С улицы"
              : ctx.driver_name
                ? ` · ${ctx.driver_name}`
                : " · Без водителя"}
          </div>
        </div>
      </header>

      <main className="flex-1 container max-w-2xl py-4 space-y-5">
        {/* Пробег */}
        <section>
          <Label htmlFor="mileage" className="text-sm">Пробег (км)</Label>
          <Input
            id="mileage"
            type="number"
            min={0}
            value={mileage ?? ""}
            onChange={(e) => setMileage(e.target.value === "" ? null : Number(e.target.value))}
            placeholder={ctx.mileage_starline == null ? "StarLine недоступен — введите вручную" : ""}
            className="mt-1"
          />
        </section>

        {/* Фото */}
        <section>
          <div className="flex items-baseline justify-between">
            <Label className="text-sm">Фото ремонта</Label>
            <span className="text-xs text-muted-foreground">
              {photos.length === 0 ? "Минимум одно фото" : `${photos.length} шт.`}
            </span>
          </div>
          <div className="grid grid-cols-3 gap-2 mt-2">
            {photos.map((p) => (
              <div key={p.presign.photo_uuid} className="relative aspect-square border rounded-md bg-muted overflow-hidden">
                {p.previewUrl && (
                  <img
                    src={p.previewUrl}
                    alt=""
                    className="absolute inset-0 w-full h-full object-cover"
                  />
                )}
                {p.status === "uploading" && (
                  <div className="absolute inset-0 flex items-center justify-center text-xs bg-black/40 text-white">
                    Загрузка…
                  </div>
                )}
                {p.status === "error" && (
                  <div className="absolute inset-0 flex items-center justify-center text-xs text-destructive p-1 text-center bg-background/85">
                    {p.errorMessage || "Ошибка"}
                  </div>
                )}
                {p.status === "uploaded" && (
                  <div className="absolute bottom-1 right-1 rounded-full bg-green-600 text-white p-1 shadow">
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M5 12l5 5L20 7" />
                    </svg>
                  </div>
                )}
                <button
                  type="button"
                  onClick={() => removePhoto(p.presign.photo_uuid)}
                  className="absolute top-1 right-1 rounded-full bg-background/80 p-1 hover:bg-background"
                >
                  <Trash2 className="h-3 w-3" />
                </button>
              </div>
            ))}
            <label className="aspect-square border-2 border-dashed rounded-md flex items-center justify-center cursor-pointer hover:bg-accent/40">
              <Camera className="h-6 w-6 text-muted-foreground" />
              <input
                type="file"
                accept="image/*"
                capture="environment"
                multiple
                className="hidden"
                onChange={(e) => onPhotoInput(e.target.files, "gallery")}
              />
            </label>
          </div>
        </section>

        {/* Работы */}
        <section>
          <div className="flex items-baseline justify-between">
            <Label className="text-sm">Работы</Label>
            <Button variant="outline" size="sm" onClick={openWorksPicker}>
              <Plus className="h-3 w-3 mr-1" />
              Добавить работу
            </Button>
          </div>
          {works.length === 0 ? (
            <div className="text-xs text-muted-foreground mt-2">Минимум одна работа</div>
          ) : (
            <ul className="mt-2 space-y-2">
              {works.map((w) => (
                <li
                  key={w.rowKey}
                  className={`rounded-md border p-2 ${w.unlocked ? "bg-amber-50 border-amber-300" : ""}`}
                >
                  <div className="flex items-start justify-between gap-2">
                    <div className="flex-1 min-w-0">
                      <div
                        className="text-sm font-medium leading-snug break-words"
                        style={{
                          display: '-webkit-box',
                          WebkitLineClamp: 2,
                          WebkitBoxOrient: 'vertical',
                          overflow: 'hidden',
                        }}
                      >
                        {w.name}
                      </div>
                      <div className="text-xs text-muted-foreground mt-0.5">
                        Прайс: {fmtPrice(w.price_catalog)} ₽
                      </div>
                    </div>
                    <div className="flex items-center gap-1">
                      <Input
                        type="number"
                        min={0}
                        value={w.price_applied}
                        disabled={!w.unlocked}
                        onChange={(e) => {
                          const v = e.target.value;
                          // Пустое поле остаётся пустым в стейте (не сбрасываем в 0),
                          // чтобы юзер мог сразу набрать новую цену поверх.
                          const next: number | "" = v === "" ? "" : Number(v);
                          setWorks((arr) =>
                            arr.map((row) =>
                              row.rowKey === w.rowKey
                                ? { ...row, price_applied: next }
                                : row,
                            ),
                          );
                        }}
                        className="w-24"
                      />
                      <Button
                        variant="ghost"
                        size="sm"
                        onClick={() => toggleWorkUnlock(w.rowKey)}
                        title={w.unlocked ? "Отменить ручную правку" : "Перебить цену"}
                      >
                        <Pencil className="h-3 w-3" />
                      </Button>
                      <Button variant="ghost" size="sm" onClick={() => removeWork(w.rowKey)}>
                        <Trash2 className="h-3 w-3" />
                      </Button>
                    </div>
                  </div>
                  {w.unlocked && (
                    <textarea
                      placeholder="Комментарий к ручной правке (обязателен)"
                      value={w.override_comment}
                      onChange={(e) =>
                        setWorks((arr) =>
                          arr.map((row) =>
                            row.rowKey === w.rowKey ? { ...row, override_comment: e.target.value } : row,
                          ),
                        )
                      }
                      className="mt-2 w-full text-sm rounded-md border bg-background p-2 min-h-[60px]"
                    />
                  )}
                </li>
              ))}
            </ul>
          )}
          {works.length > 0 && (
            <div className="mt-3 text-right text-sm font-medium">Итого: {fmtPrice(totalSum)} ₽</div>
          )}
        </section>

        {/* Механики (делёж 1/N) */}
        <MechanicsField value={mechanics} onChange={setMechanics} totalSum={totalSum} />

        {/* Запчасти */}
        <section>
          <Label className="text-sm">Запчасти и материалы</Label>
          {parts.length > 0 && (
            <ul className="mt-2 space-y-1">
              {parts.map((p) => (
                <li key={p.rowKey} className="flex items-center gap-2 text-sm">
                  <span className="flex-1">{p.name}</span>
                  <Input
                    type="number"
                    min={1}
                    value={p.qty}
                    onChange={(e) =>
                      setParts((arr) =>
                        arr.map((row) =>
                          row.rowKey === p.rowKey ? { ...row, qty: Math.max(1, Number(e.target.value)) } : row,
                        ),
                      )
                    }
                    className="w-20"
                  />
                  <Button variant="ghost" size="sm" onClick={() => removePart(p.rowKey)}>
                    <Trash2 className="h-3 w-3" />
                  </Button>
                </li>
              ))}
            </ul>
          )}
          <div className="mt-2 flex gap-2">
            <Input
              value={partsDraft.name}
              onChange={(e) => queryPartSuggestions(e.target.value)}
              placeholder="Например, Свеча NGK"
              onKeyDown={(e) => e.key === "Enter" && addPart(partsDraft.name)}
            />
            <Button onClick={() => addPart(partsDraft.name)}>
              <Plus className="h-4 w-4" />
            </Button>
          </div>
          {partsDraft.suggestions.length > 0 && (
            <ul className="mt-1 border rounded-md bg-popover divide-y">
              {partsDraft.suggestions.map((s) => (
                <li key={s}>
                  <button
                    type="button"
                    className="w-full text-left text-sm px-3 py-2 hover:bg-accent/40"
                    onClick={() => addPart(s)}
                  >
                    {s}
                  </button>
                </li>
              ))}
            </ul>
          )}
        </section>

        {/* Замена масла */}
        <section className="border rounded-md p-3">
          <label className="flex items-center gap-2 text-sm font-medium">
            <input
              type="checkbox"
              checked={oilChange.enabled}
              onChange={(e) =>
                setOilChange((oc) => ({ ...oc, enabled: e.target.checked }))
              }
            />
            Была замена масла
          </label>
          {oilChange.enabled && (
            <div className="mt-3 space-y-3">
              <div>
                <Label className="text-sm">Следующая замена через (км)</Label>
                <Input
                  type="number"
                  min={0}
                  value={oilChange.next_in_km}
                  onChange={(e) =>
                    setOilChange((oc) => ({ ...oc, next_in_km: Number(e.target.value) || 0 }))
                  }
                />
              </div>
              <div>
                <Label className="text-sm">Фото стикера (одно)</Label>
                <label className="mt-1 block border-2 border-dashed rounded-md text-center cursor-pointer hover:bg-accent/40 overflow-hidden relative aspect-video">
                  {oilChange.sticker?.previewUrl ? (
                    <img
                      src={oilChange.sticker.previewUrl}
                      alt=""
                      className="absolute inset-0 w-full h-full object-contain bg-muted"
                    />
                  ) : (
                    <div className="absolute inset-0 flex items-center justify-center">
                      <span className="text-sm text-muted-foreground">Тап чтобы загрузить</span>
                    </div>
                  )}
                  {oilChange.sticker?.status === "uploading" && (
                    <div className="absolute inset-0 flex items-center justify-center text-xs bg-black/40 text-white">
                      Загрузка…
                    </div>
                  )}
                  {oilChange.sticker?.status === "error" && (
                    <div className="absolute inset-0 flex items-center justify-center text-xs text-destructive p-2 bg-background/85 text-center">
                      Ошибка: {oilChange.sticker.errorMessage}
                    </div>
                  )}
                  {oilChange.sticker?.status === "uploaded" && (
                    <div className="absolute bottom-1 right-1 rounded-full bg-green-600 text-white p-1 shadow">
                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M5 12l5 5L20 7" />
                      </svg>
                    </div>
                  )}
                  <input
                    type="file"
                    accept="image/*"
                    capture="environment"
                    className="hidden"
                    onChange={(e) => onPhotoInput(e.target.files, "sticker")}
                  />
                </label>
              </div>
            </div>
          )}
        </section>
      </main>

      {/* Works picker modal — общий компонент (см. WorksPickerModal) */}
      {worksPicker.open && (
        <WorksPickerModal
          query={worksPicker.q}
          results={worksPicker.results}
          onQuery={queryWorks}
          onPick={addWorkFromCatalog}
          onClose={() => setWorksPicker({ open: false, q: "", results: [] })}
        />
      )}
    </div>
  );
}
