/* ============================================================
   ui.jsx — shared widgets exported to window.
   PointsScale, RatingPips, ProgressBar, Cover, LinkChip,
   SectionRule, Toaster, etc.
   ============================================================ */
const React = window.React;
const { useState, useEffect, useRef } = React;
const Icon = window.Icon;

/* ---- Toaster -------------------------------------------------- */
let toastListeners = new Set();
window.pushToast = (t) => toastListeners.forEach((f) => f(t));

function Toaster() {
  const [items, setItems] = useState([]);
  useEffect(() => {
    const on = (t) => {
      setItems((arr) => [...arr, t]);
      setTimeout(() => setItems((arr) => arr.filter((x) => x.id !== t.id)), 2400);
    };
    toastListeners.add(on);
    return () => toastListeners.delete(on);
  }, []);
  return (
    <div className="toast-wrap">
      {items.map((t) => (
        <div className="toast" key={t.id}>
          <span>{t.text}</span>
          {t.pts !== 0 && t.pts != null && (
            <span className="toast__pts">{t.pts > 0 ? "+" : ""}{t.pts} PTS</span>
          )}
        </div>
      ))}
    </div>
  );
}
window.Toaster = Toaster;

/* ---- Points scale: ring / bar / thermo (single combined total) - */
function PointsRing({ day, size = 220, thick = 22 }) {
  const { net, target } = day;
  const r = (size - thick) / 2;
  const c = 2 * Math.PI * r;
  const frac = Math.max(0, Math.min(net / Math.max(target, 1), 1));
  const over = net >= target;
  const cx = size / 2;
  return (
    <div className="ring-wrap">
      <svg width={size} height={size}>
        <circle cx={cx} cy={cx} r={r} fill="none" stroke="var(--paper-20)" strokeWidth={thick} />
        <circle cx={cx} cy={cx} r={r} fill="none" stroke="var(--ink-100)" strokeWidth={1} opacity="0.25"
          strokeDasharray={`1 ${c / 24 - 1}`} transform={`rotate(-90 ${cx} ${cx})`} />
        <circle cx={cx} cy={cx} r={r} fill="none" stroke={over ? "var(--signal)" : "var(--ink-100)"} strokeWidth={thick}
          strokeDasharray={`${c * frac} ${c}`} strokeLinecap="butt"
          transform={`rotate(-90 ${cx} ${cx})`} />
      </svg>
      <div className="ring-center">
        <div>
          <div className="ring-total" style={{ fontSize: size * 0.26 }}>{net}</div>
          <div className="ring-of">из {target}</div>
          {over && <div className="task__pts pts-pos" style={{ marginTop: 4 }}>цель взята</div>}
        </div>
      </div>
    </div>
  );
}

function PointsBar({ day }) {
  const { net, target } = day;
  const cap = Math.max(target, net, 1);
  const pct = (v) => (Math.max(v, 0) / cap) * 100;
  return (
    <div className="scalebar">
      <div className="scalebar__track">
        <div className="scalebar__seg scalebar__seg--task" style={{ width: pct(net) + "%" }} />
      </div>
      <div className="scalebar__ticks">
        <span className="scalebar__tick">0</span>
        <span className="scalebar__tick" style={{ position: "relative", left: (pct(target) - 50) + "%" }}>цель {target}</span>
        <span className="scalebar__tick">{Math.round(cap)}</span>
      </div>
    </div>
  );
}

function PointsThermo({ day, h = 240 }) {
  const { net, target } = day;
  const cap = Math.max(target * 1.15, net, 1);
  const px = (v) => (Math.max(v, 0) / cap) * h;
  return (
    <div className="thermo">
      <div className="thermo__tube" style={{ height: h }}>
        <div className="thermo__fill-task" style={{ height: px(net) }} />
        <div className="thermo__target" style={{ bottom: px(target) }} />
      </div>
      <div className="thermo__labels">
        <div><div className="e-label">Баллы за день</div><div className="ring-total" style={{ fontSize: 40 }}>{net}</div></div>
        <div className="legend-row mono" style={{ color: "var(--text-muted)" }}>Цель — - - {target}</div>
      </div>
    </div>
  );
}

window.PointsScale = function PointsScale({ day, variant = "ring" }) {
  if (variant === "bar") return <PointsBar day={day} />;
  if (variant === "thermo") return <PointsThermo day={day} />;
  return (
    <div className="ring-card">
      <PointsRing day={day} />
      <div className="ring-legend">
        <div className="legend-row"><span className="legend-swatch" style={{ background: "var(--ink-100)" }} />Баллы за день<span className="legend-val">{day.net}<span className="muted" style={{ fontWeight: 400 }}> /{day.target}</span></span></div>
        <div className="legend-row"><span className="legend-swatch" style={{ background: "var(--paper-30)" }} />Осталось до цели<span className="legend-val">{Math.max(day.target - day.net, 0)}</span></div>
      </div>
    </div>
  );
};

/* ---- Rating pips ---------------------------------------------- */
window.RatingPips = function RatingPips({ value = 0, max = 5, onChange }) {
  return (
    <div className="rating">
      {Array.from({ length: max }).map((_, i) => (
        <div key={i}
          className={"rating__pip" + (i < value ? " rating__pip--on" : "")}
          onClick={onChange ? (e) => { e.stopPropagation(); onChange(i + 1 === value ? 0 : i + 1); } : undefined}
          style={{ cursor: onChange ? "pointer" : "default" }} />
      ))}
    </div>
  );
};

/* ---- Progress bar --------------------------------------------- */
window.ProgressBar = function ProgressBar({ value, total, ink = false }) {
  const pct = total ? Math.min((value / total) * 100, 100) : 0;
  return <div className={"pbar" + (ink ? " pbar--ink" : "")}><i style={{ width: pct + "%" }} /></div>;
};

/* ---- Cover ---------------------------------------------------- */
window.Cover = function Cover({ m, onClick, showBar = true }) {
  const c = m.cover;
  const pct = m.progress.total ? (m.progress.current / m.progress.total) * 100 : 0;
  const kick = { fiction: "Худ. лит.", science: "Наука", video: "Видео" }[m.type];
  const hasImg = !!m.coverImg;
  const bgStyle = hasImg
    ? { backgroundImage: `url(${m.coverImg})`, backgroundSize: "cover", backgroundPosition: "center", color: "#fff" }
    : { background: `linear-gradient(150deg, ${c.from}, ${c.to})`, color: c.fg };
  if (m.type === "video") {
    return (
      <div className="cover cover--video" onClick={onClick} style={bgStyle}>
        {hasImg && <div style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.35)" }} />}
        <div className="cover__kicker" style={{ position: "relative" }}>{kick}</div>
        <span className="cover__playmid" style={{ position: "relative" }}><Icon name="play" size={18} fill /></span>
        <div className="cover__vidfoot" style={{ position: "relative" }}>
          <div className="cover__title">{m.title}</div>
          <span className="mono nowrap" style={{ fontSize: 12, opacity: 0.85 }}>{m.progress.current}/{m.progress.total} {m.progress.unit}</span>
        </div>
        {showBar && pct > 0 && <div className="cover__bar"><i style={{ width: pct + "%" }} /></div>}
      </div>
    );
  }
  return (
    <div className="cover" onClick={onClick} style={bgStyle}>
      {hasImg && <div style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.35)" }} />}
      <div className="cover__kicker" style={{ position: "relative" }}>{kick}</div>
      <div style={{ position: "relative" }}>
        <div className="cover__title">{m.title}</div>
        {m.author && m.author !== "—" && <div className="cover__author">{m.author}</div>}
      </div>
      {showBar && pct > 0 && <div className="cover__bar"><i style={{ width: pct + "%" }} /></div>}
    </div>
  );
};

/* ---- Link chip ------------------------------------------------ */
const KIND_DOT = { material: "var(--ink-100)", course: "var(--signal)", note: "var(--paper-30)", task: "var(--ok)" };
const KIND_LABEL = { material: "Материал", course: "Курс", note: "Заметка", task: "Задача" };
window.LinkChip = function LinkChip({ entity, onClick }) {
  if (!entity) return null;
  const k = entity._kind;
  return (
    <span className="link-chip" onClick={onClick}>
      <span className="link-chip__dot" style={{ background: KIND_DOT[k] }} />
      <span className="link-chip__kind">{KIND_LABEL[k]}</span>
      <span>{entity.title}</span>
    </span>
  );
};

/* ---- Section rule --------------------------------------------- */
window.SectionRule = function SectionRule({ children, kicker, right }) {
  return (
    <div className="section-rule">
      {kicker && <span className="eyebrow-mono">{kicker}</span>}
      <span className="section-rule__title">{children}</span>
      <span className="section-rule__line" />
      {right}
    </div>
  );
};

/* ---- Status badge --------------------------------------------- */
const STATUS = {
  reading: { label: "Читаю", cls: "" }, done: { label: "Готово", cls: "ok" },
  queue: { label: "В очереди", cls: "muted" }, paused: { label: "Пауза", cls: "warn" },
};
window.StatusBadge = function StatusBadge({ status }) {
  const s = STATUS[status] || STATUS.queue;
  const color = { ok: "var(--ok)", warn: "var(--warn)", muted: "var(--text-faint)", "": "var(--signal)" }[s.cls];
  return (
    <span className="e-label" style={{ display: "inline-flex", alignItems: "center", gap: 6, color }}>
      <span className="dot" style={{ background: color }} />{s.label}
    </span>
  );
};

/* ---- IconBtn / mono button ------------------------------------ */
window.GButton = function GButton({ children, icon, variant = "default", onClick, type, style }) {
  const base = {
    appearance: "none", cursor: "pointer", fontFamily: "var(--font-mono)",
    fontSize: "var(--t-meta)", letterSpacing: "0.04em", textTransform: "uppercase",
    border: "2px solid var(--ink-100)", padding: "10px 16px",
    display: "inline-flex", alignItems: "center", gap: 8, fontWeight: 700, whiteSpace: "nowrap",
    transition: "all 90ms cubic-bezier(0.2,0,0,1)",
  };
  const variants = {
    default: { background: "var(--paper-00)", color: "var(--ink-100)" },
    signal: { background: "var(--signal)", color: "#fff", borderColor: "var(--signal)" },
    ink: { background: "var(--ink-100)", color: "var(--paper-00)" },
    ghost: { background: "transparent", color: "var(--ink-100)", border: "1px solid var(--ink-100)" },
  };
  return (
    <button type={type || "button"} onClick={onClick}
      onMouseEnter={(e) => { e.currentTarget.style.boxShadow = "var(--shadow-tap)"; e.currentTarget.style.transform = "translate(-1px,-1px)"; }}
      onMouseLeave={(e) => { e.currentTarget.style.boxShadow = "none"; e.currentTarget.style.transform = "none"; }}
      style={{ ...base, ...variants[variant], ...style }}>
      {icon && <Icon name={icon} size={16} />}{children}
    </button>
  );
};

/* ---- Tag ------------------------------------------------------ */
window.GTag = function GTag({ children, active, onClick }) {
  return (
    <span onClick={onClick}
      style={{
        fontFamily: "var(--font-mono)", fontSize: "var(--t-micro)", letterSpacing: "0.06em",
        textTransform: "uppercase", padding: "3px 10px", borderRadius: 999,
        border: "1px solid " + (active ? "var(--signal)" : "var(--ink-40)"),
        background: active ? "var(--signal)" : "transparent",
        color: active ? "#fff" : "var(--text-muted)",
        cursor: onClick ? "pointer" : "default", whiteSpace: "nowrap",
      }}>#{children}</span>
  );
};

Object.assign(window, { Toaster, PointsRing });

/* ---- TimeLogger: stopwatch (H:M:S) + accumulated time --------- */
window.TimeLogger = function TimeLogger({ timer, kind, id, today, week, onStart, onStop }) {
  const clock = window.fmtClock;
  const running = timer && timer.kind === kind && timer.id === id;
  const elapsed = running ? Math.max(0, Math.round((Date.now() - timer.at) / 1000)) : 0;
  return (
    <span className="tlog">
      {running ? (
        <button className="tlog__run" onClick={(e) => { e.stopPropagation(); onStop(); }} title="Остановить секундомер">
          <span className="tlog__rec" />
          <span className="tlog__clock">{clock(elapsed)}</span>
          <Icon name="stop" size={11} fill />
        </button>
      ) : (
        <button className="tlog__start" onClick={(e) => { e.stopPropagation(); onStart(kind, id); }} title="Запустить секундомер">
          <Icon name="play" size={11} fill />старт
        </button>
      )}
      <span className="tlog__chip tlog__chip--static" title="Учтёно · часы:минуты:секунды">
        <Icon name="clock" size={12} />
        <span className="mono">{clock(today)}</span>
        <span className="tlog__sep">·</span>
        <span className="mono muted">нед {clock(week)}</span>
      </span>
    </span>
  );
};

/* ---- TimeBlock: stopwatch + total + history (detail pages) ---- */
window.TimeBlock = function TimeBlock({ log, todayIdx, timer, kind, id, onStart, onStop, label = "Время" }) {
  const clock = window.fmtClock;
  const total = window.timeWeek(log);
  const today = window.timeToday(log, todayIdx);
  const running = timer && timer.kind === kind && timer.id === id;
  const elapsed = running ? Math.max(0, Math.round((Date.now() - timer.at) / 1000)) : 0;
  const DAY = window.DAY_NAMES, DATES = window.WEEK_DATES;
  const byDay = {};
  (log || []).forEach((e) => { byDay[e.d] = (byDay[e.d] || 0) + window.entrySec(e); });
  const days = Object.keys(byDay).map(Number).sort((a, b) => a - b);
  const max = Math.max(1, ...days.map((d) => byDay[d]));
  return (
    <div className="task" style={{ display: "block", padding: "var(--s-5)" }}>
      <window.SectionRule kicker="Секундомер">{label}</window.SectionRule>

      <div className={"sw" + (running ? " sw--on" : "")}>
        <div className="sw__face">
          {running && <span className="sw__rec" />}
          <span className="sw__clock">{clock(running ? elapsed : today)}</span>
        </div>
        <div className="sw__meta">
          <span className="e-label">{running ? "идёт запись" : "сегодня · ч:м:с"}</span>
          {running
            ? <window.GButton variant="signal" icon="stop" onClick={onStop} style={{ width: "100%", justifyContent: "center" }}>Стоп · записать</window.GButton>
            : <window.GButton variant="ink" icon="play" onClick={() => onStart(kind, id)} style={{ width: "100%", justifyContent: "center" }}>Старт секундомера</window.GButton>}
        </div>
      </div>

      <div className="row-3" style={{ justifyContent: "space-between", alignItems: "baseline", margin: "var(--s-4) 0 var(--s-3)" }}>
        <span className="e-label">Всего за неделю</span>
        <span className="time-big" style={{ fontSize: "var(--t-h2)" }}>{clock(total)}</span>
      </div>

      {days.length > 0 ? (
        <div className="thist" style={{ marginTop: "var(--s-4)" }}>
          {days.map((d) => (
            <div className="thist__row" key={d}>
              <span className="thist__date">{DAY[d]} {DATES[d]}</span>
              <span className="thist__bar"><i style={{ width: (byDay[d] / max) * 100 + "%" }} /></span>
              <span className="thist__min">{clock(byDay[d])}</span>
            </div>
          ))}
        </div>
      ) : (
        <div className="muted" style={{ fontSize: "var(--t-small)", marginTop: 12 }}>Пока нет записей о времени. Запустите секундомер.</div>
      )}
    </div>
  );
};
window.Stepper = function Stepper({ value, onChange, step = 5, min = 0, suffix }) {
  return (
    <span className="stepper">
      <button className="stepper__btn" onClick={() => onChange(Math.max(min, value - step))}><Icon name="minus" size={15} /></button>
      <input className="stepper__in" type="number" value={value} min={min}
        onChange={(e) => onChange(Math.max(min, Number(e.target.value) || 0))} />
      {suffix && <span className="stepper__suf">{suffix}</span>}
      <button className="stepper__btn" onClick={() => onChange(value + step)}><Icon name="plus" size={15} /></button>
    </span>
  );
};

/* ---- MoodEntry: 7 diverging −5..+5 scales ---------------------- */
window.MoodEntry = function MoodEntry({ mood, onChange }) {
  const Q = window.MOOD_QUESTIONS;
  const range = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5];
  return (
    <div className="stack-4">
      {Q.map((q) => {
        const v = mood && mood[q.id] != null ? mood[q.id] : null;
        return (
          <div className="mood-row" key={q.id}>
            <div className="mood-row__head">
              <span className="mood-row__label">{q.label}</span>
              <span className="mood-row__val mono" style={{ color: v == null ? "var(--text-faint)" : v < 0 ? "var(--signal)" : "var(--ink-100)" }}>
                {v == null ? "—" : (v > 0 ? "+" : "") + v}
              </span>
            </div>
            <div className="mood-cells">
              {range.map((n) => (
                <button key={n}
                  className={"mood-cell" + (n === 0 ? " mood-cell--zero" : n < 0 ? " mood-cell--neg" : " mood-cell--pos") + (v === n ? " mood-cell--on" : "")}
                  onClick={() => onChange(q.id, n)} title={String(n)} />
              ))}
            </div>
            <div className="mood-poles"><span>{q.lo}</span><span>{q.hi}</span></div>
          </div>
        );
      })}
    </div>
  );
};

/* ---- MoodBars: read-only diverging bars (for stats) ----------- */
window.MoodBars = function MoodBars({ mood, weekAvg }) {
  const Q = window.MOOD_QUESTIONS;
  return (
    <div className="stack-3">
      {Q.map((q) => {
        const v = mood && mood[q.id] != null ? mood[q.id] : 0;
        const wk = weekAvg && weekAvg[q.id] != null ? weekAvg[q.id] : null;
        return (
          <div className="mbar" key={q.id}>
            <span className="mbar__label">{q.label}</span>
            <div className="mbar__track">
              <span className="mbar__center" />
              {v !== 0 && (
                <span className="mbar__fill" style={{
                  background: v < 0 ? "var(--signal)" : "var(--ink-100)",
                  left: v < 0 ? (50 + v * 10) + "%" : "50%",
                  width: Math.abs(v) * 10 + "%",
                }} />
              )}
              {wk != null && <span className="mbar__tick" style={{ left: (50 + wk * 10) + "%" }} title={"среднее " + wk.toFixed(1)} />}
            </div>
            <span className="mbar__val mono" style={{ color: v < 0 ? "var(--signal)" : "var(--ink-100)" }}>{v > 0 ? "+" : ""}{v}</span>
          </div>
        );
      })}
    </div>
  );
};
