/* ui.jsx — мелкие примитивы и хелперы. Экспортируются в window.
 * Категории теперь динамические — берутся из window.Store (см. store.jsx).
 * Здесь только catFrom() как безопасный геттер на случай раннего рендера. */

const catFrom = (k) => (window.catOf ? window.catOf(k) : { key: k || "other", label: "Прочее", color: "gray" });
const colorClassFrom = (c) => (window.colorClass ? window.colorClass(c) : "cat-c-gray");

/* ----------------------------------------------------------- даты (рус.) */
const MONTHS = ["янв.", "февр.", "марта", "апр.", "мая", "июня", "июля", "авг.", "сент.", "окт.", "нояб.", "дек."];
const MONTHS_FULL = ["января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"];

function startOfDay(d) { const x = new Date(d); x.setHours(0,0,0,0); return x; }
function dayDiff(a, b) { return Math.round((startOfDay(a) - startOfDay(b)) / 86400e3); }
function hhmm(d) { return new Date(d).toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" }); }

// «сегодня 14:30», «вчера», «3 июня»
function formatCreated(iso) {
  const d = new Date(iso);
  const diff = dayDiff(new Date(), d);
  if (diff === 0) return "сегодня " + hhmm(d);
  if (diff === 1) return "вчера";
  if (diff > 1 && diff < 7) return diff + " дн. назад";
  return d.getDate() + " " + MONTHS[d.getMonth()] + (d.getFullYear() !== new Date().getFullYear() ? " " + d.getFullYear() : "");
}

// для напоминаний: «сегодня 10:00», «завтра 09:00», «просрочено», «через 3 дня»
function formatRemind(iso) {
  const d = new Date(iso);
  const diff = dayDiff(d, new Date());
  const past = d < new Date();
  let when;
  if (diff === 0) when = "сегодня " + hhmm(d);
  else if (diff === 1) when = "завтра " + hhmm(d);
  else if (diff === -1) when = "вчера " + hhmm(d);
  else when = d.getDate() + " " + MONTHS_FULL[d.getMonth()] + ", " + hhmm(d);
  let tone = "future";
  if (past) tone = "overdue";
  else if (diff === 0) tone = "today";
  else if (diff === 1) tone = "tomorrow";
  return { text: when, tone };
}

// значение для <input type="datetime-local">
function toLocalInput(iso) {
  if (!iso) return "";
  const d = new Date(iso);
  const pad = (n) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
function fromLocalInput(v) { return v ? new Date(v).toISOString() : null; }

/* ----------------------------------------------------------- иконки (24px stroke) */
function Icon({ name, size = 20, className = "", strokeWidth = 1.75 }) {
  const p = {
    notes: <><path d="M5 3.5h11l4 4V20a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z"/><path d="M15 3.5V8h4.5"/><path d="M8 12h8M8 16h5"/></>,
    search: <><circle cx="11" cy="11" r="6.5"/><path d="m20 20-3.6-3.6"/></>,
    bell: <><path d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6Z"/><path d="M10.5 19a1.6 1.6 0 0 0 3 0"/></>,
    plus: <><path d="M12 5v14M5 12h14"/></>,
    close: <><path d="m6 6 12 12M18 6 6 18"/></>,
    trash: <><path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"/></>,
    sun: <><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4 12H2m20 0h-2M5 5 4 4m16 1 1-1M5 19l-1 1m16-1 1 1"/></>,
    moon: <><path d="M20 14.5A8 8 0 0 1 9.5 4 8 8 0 1 0 20 14.5Z"/></>,
    telegram: <><path d="M21 5 3 12l5 1.8L18 7.5 9.5 15v4l3-3 4.5 3L21 5Z"/></>,
    web: <><circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17M12 3.5c2.4 2.3 3.7 5.3 3.7 8.5S14.4 18.2 12 20.5C9.6 18.2 8.3 15.2 8.3 12S9.6 5.8 12 3.5Z"/></>,
    chevron: <><path d="m9 6 6 6-6 6"/></>,
    logout: <><path d="M15 4h3a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3M10 8l-4 4 4 4M6 12h10"/></>,
    sparkles: <><path d="M12 3l1.8 4.7L18.5 9.5 13.8 11.3 12 16l-1.8-4.7L5.5 9.5l4.7-1.8L12 3Z"/><path d="M18.5 15.5l.8 2 2 .8-2 .8-.8 2-.8-2-2-.8 2-.8.8-2Z"/></>,
    tag: <><path d="M3.5 11.5 11 4h7a1 1 0 0 1 1 1v7l-7.5 7.5a1.5 1.5 0 0 1-2.1 0L3.5 13.6a1.5 1.5 0 0 1 0-2.1Z"/><circle cx="15" cy="9" r="1.2"/></>,
    check: <><path d="m5 12.5 4.5 4.5L19 6.5"/></>,
    edit: <><path d="M4 20h4l10-10-4-4L4 16v4Z"/><path d="m14 6 4 4"/></>,
    menu: <><path d="M4 7h16M4 12h16M4 17h16"/></>,
    calendar: <><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M4 9h16M8 3v4m8-4v4"/></>,
    arrowRight: <><path d="M5 12h14M13 6l6 6-6 6"/></>,
    inbox: <><path d="M4 13h4l1.5 3h5L16 13h4"/><path d="M4 13 6 5h12l2 8v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-6Z"/></>,
    lock: <><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></>,
    key: <><circle cx="8" cy="15" r="4"/><path d="m11 12 8-8M16 4l3 3M14.5 6.5 17 9"/></>,
    eye: <><path d="M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12Z"/><circle cx="12" cy="12" r="3"/></>,
    eyeOff: <><path d="m4 4 16 16"/><path d="M9.6 5.6A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-3 3.6M6.2 7.3A16 16 0 0 0 2.5 12S6 18.5 12 18.5a9 9 0 0 0 3.3-.6"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/></>,
    copy: <><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a1 1 0 0 1 1-1h9"/></>,
    settings: <><circle cx="12" cy="12" r="3"/><path d="M19.4 13.5a7.8 7.8 0 0 0 0-3l1.7-1.3-1.7-3-2 .8a7.5 7.5 0 0 0-2.6-1.5L14.2 3h-3.4l-.3 2a7.5 7.5 0 0 0-2.6 1.5l-2-.8-1.7 3L5.6 9a7.8 7.8 0 0 0 0 3l-1.7 1.3 1.7 3 2-.8a7.5 7.5 0 0 0 2.6 1.5l.3 2h3.4l.3-2a7.5 7.5 0 0 0 2.6-1.5l2 .8 1.7-3-1.7-1.3Z"/></>,
    paperclip: <><path d="M19 11.5 12 18.5a4.5 4.5 0 0 1-6.4-6.4l7-7a3 3 0 0 1 4.3 4.3l-7 7a1.5 1.5 0 0 1-2.2-2.1l6.3-6.3"/></>,
    image: <><rect x="3.5" y="4.5" width="17" height="15" rx="2.5"/><circle cx="8.5" cy="9.5" r="1.8"/><path d="m4 17 4.5-4.5 3.5 3.5 3-3 5.5 5"/></>,
    video: <><rect x="3" y="6" width="13" height="12" rx="2.5"/><path d="m16 10 5-3v10l-5-3z"/></>,
    link: <><path d="M9.5 14.5a3.5 3.5 0 0 0 5 0l3-3a3.5 3.5 0 0 0-5-5l-1.2 1.2"/><path d="M14.5 9.5a3.5 3.5 0 0 0-5 0l-3 3a3.5 3.5 0 0 0 5 5l1.2-1.2"/></>,
    external: <><path d="M14 4h6v6M20 4l-9 9M19 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h5"/></>,
    refresh: <><path d="M4 12a8 8 0 0 1 13.7-5.6L20 8M20 4v4h-4M20 12a8 8 0 0 1-13.7 5.6L4 16M4 20v-4h4"/></>,
    star: <><path d="M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 17l-5.2 2.7 1-5.8L3.5 9.7l5.9-.9L12 3.5Z"/></>,
    grid: <><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></>,
    rows: <><rect x="4" y="5" width="16" height="5" rx="1.5"/><rect x="4" y="14" width="16" height="5" rx="1.5"/></>,
    mic: <><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3M9 21h6"/></>,
  }[name];
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth={strokeWidth} strokeLinecap="round"
      strokeLinejoin="round" className={className} aria-hidden="true">{p}</svg>
  );
}

/* ----------------------------------------------------------- бейдж категории */
function CategoryBadge({ category, size = "md" }) {
  const c = catFrom(category);
  const pad = size === "sm" ? "px-2 py-0.5 text-[11px]" : "px-2.5 py-1 text-xs";
  return (
    <span className={`inline-flex items-center gap-1.5 rounded-full font-semibold ${pad} ${colorClassFrom(c.color)}`}>
      <span className="cat-dot" />
      {c.label}
    </span>
  );
}

/* ----------------------------------------------------------- копирование */
function pluralRu(n, one, few, many) {
  const m10 = n % 10, m100 = n % 100;
  if (m10 === 1 && m100 !== 11) return one;
  if (m10 >= 2 && m10 <= 4 && (m100 < 10 || m100 >= 20)) return few;
  return many;
}
function copyToClipboard(text) {  if (navigator.clipboard && navigator.clipboard.writeText) return navigator.clipboard.writeText(text);
  return new Promise((res) => {
    const ta = document.createElement("textarea");
    ta.value = text; ta.style.position = "fixed"; ta.style.opacity = "0";
    document.body.appendChild(ta); ta.select();
    try { document.execCommand("copy"); } catch (e) {}
    document.body.removeChild(ta); res();
  });
}

/* ----------------------------------------------------------- генератор паролей */
function generatePassword({ length = 16, upper = true, digits = true, symbols = true } = {}) {
  const lo = "abcdefghijkmnpqrstuvwxyz";
  const up = "ABCDEFGHJKLMNPQRSTUVWXYZ";
  const di = "23456789";
  const sy = "!@#$%^&*-_=+?";
  let pool = lo;
  const must = [pick(lo)];
  if (upper) { pool += up; must.push(pick(up)); }
  if (digits) { pool += di; must.push(pick(di)); }
  if (symbols) { pool += sy; must.push(pick(sy)); }
  const out = [...must];
  for (let i = out.length; i < length; i++) out.push(pick(pool));
  // перемешать (Fisher–Yates с crypto)
  for (let i = out.length - 1; i > 0; i--) {
    const j = rnd(i + 1);
    [out[i], out[j]] = [out[j], out[i]];
  }
  return out.join("");
  function pick(s) { return s[rnd(s.length)]; }
  function rnd(n) {
    if (window.crypto && window.crypto.getRandomValues) {
      const a = new Uint32Array(1); window.crypto.getRandomValues(a);
      return a[0] % n;
    }
    return Math.floor(Math.random() * n);
  }
}

// сила пароля → {score 0..4, label, tone}
function passwordStrength(pw) {
  if (!pw) return { score: 0, label: "—", tone: "gray" };
  let s = 0;
  if (pw.length >= 8) s++;
  if (pw.length >= 14) s++;
  if (/[a-z]/.test(pw) && /[A-Z]/.test(pw)) s++;
  if (/\d/.test(pw)) s++;
  if (/[^A-Za-z0-9]/.test(pw)) s++;
  const score = Math.min(4, s);
  const map = [
    { label: "Слабый", tone: "red" },
    { label: "Слабый", tone: "red" },
    { label: "Средний", tone: "amber" },
    { label: "Хороший", tone: "teal" },
    { label: "Надёжный", tone: "green" },
  ];
  return { score, ...map[score] };
}

/* ----------------------------------------------------------- пилюля тега */
function TagPill({ children, onRemove }) {
  return (
    <span className="inline-flex items-center gap-1 rounded-full bg-[var(--surface-2)] border border-[var(--border)] px-2 py-0.5 text-[11px] text-[var(--muted)]">
      <span className="opacity-60">#</span>{children}
      {onRemove && (
        <button onClick={onRemove} className="ml-0.5 -mr-0.5 opacity-50 hover:opacity-100 transition" aria-label="Удалить тег">
          <Icon name="close" size={12} strokeWidth={2.2} />
        </button>
      )}
    </span>
  );
}

/* ----------------------------------------------------------- источник */
function SourceMark({ source }) {
  const settings = window.Store ? Store.useSettings() : { showSource: true };
  if (settings.showSource === false) return null;
  const tg = source === "telegram";
  return (
    <span className="inline-flex items-center gap-1 text-[var(--muted)]" title={tg ? "Из Telegram" : "Из веба"}>
      <Icon name={tg ? "telegram" : "web"} size={14} strokeWidth={1.6} />
    </span>
  );
}

/* ----------------------------------------------------------- кнопки */
function Button({ children, variant = "primary", size = "md", className = "", ...rest }) {
  const sizes = { sm: "h-8 px-3 text-[13px]", md: "h-10 px-4 text-sm", lg: "h-11 px-5 text-sm" };
  const variants = {
    primary: "btn-primary",
    ghost: "btn-ghost",
    soft: "btn-soft",
    danger: "btn-danger",
  };
  return (
    <button className={`inline-flex items-center justify-center gap-2 rounded-xl font-semibold transition active:scale-[.98] disabled:opacity-50 disabled:pointer-events-none ${sizes[size]} ${variants[variant]} ${className}`} {...rest}>
      {children}
    </button>
  );
}

/* ----------------------------------------------------------- спиннер / скелетон */
function Spinner({ size = 18 }) {
  return <span className="spinner" style={{ width: size, height: size }} />;
}
function SkeletonCard() {
  return (
    <div className="rounded-2xl border border-[var(--border)] bg-[var(--surface)] p-4 sm:p-5">
      <div className="flex items-center gap-2 mb-3">
        <div className="sk h-5 w-20 rounded-full" />
        <div className="sk h-4 w-16 rounded ml-auto" />
      </div>
      <div className="sk h-5 w-3/4 rounded mb-2" />
      <div className="sk h-4 w-1/2 rounded mb-4" />
      <div className="flex gap-2">
        <div className="sk h-5 w-14 rounded-full" />
        <div className="sk h-5 w-16 rounded-full" />
      </div>
    </div>
  );
}

Object.assign(window, {
  catFrom, colorClassFrom,
  formatCreated, formatRemind, toLocalInput, fromLocalInput, hhmm, MONTHS_FULL,
  Icon, CategoryBadge, TagPill, SourceMark, Button, Spinner, SkeletonCard,
  copyToClipboard, generatePassword, passwordStrength, pluralRu,
});
