// Корневой компонент: состояние, фильтры, масштаб, тулбар, сборка строк.
const { useState, useMemo, useEffect, useRef } = React;

// Пресеты масштаба: имя → видимое окно в мс (центрируется на «сейчас» при выборе).
const HOUR = D.HOUR, DAY = D.DAY;
const SCALES = [
  { id: "week", label: "Неделя", span: 7 * DAY, minPx: 64 },
  { id: "2week", label: "2 недели", span: 14 * DAY, minPx: 70 },
  { id: "month", label: "Месяц", span: 30 * DAY, minPx: 80 },
  { id: "range", label: "Весь диапазон", span: D.RANGE_END - D.RANGE_START, minPx: 90 },
];

function App() {
  // Видимость групп / скрытые КА.
  const [groupShown, setGroupShown] = useState(() => {
    const o = {}; D.GROUP_DEFS.forEach((g) => (o[g.id] = true)); return o;
  });
  const [scHidden, setScHidden] = useState(() => new Set());
  const [typeFilter, setTypeFilter] = useState({ optical: true, radar: true, combo: true });
  const [search, setSearch] = useState("");
  const [scaleId, setScaleId] = useState("week");
  const [selectedIv, setSelectedIv] = useState(null);
  const [selectedSc, setSelectedSc] = useState(null);
  const [timelineCollapsed, setTimelineCollapsed] = useState(() => new Set());
  const [scrollSignal, setScrollSignal] = useState(0);
  const [winCenter, setWinCenter] = useState(D.NOW);

  const byId = useMemo(() => {
    const m = {}; D.plans.forEach((iv) => (m[iv.id] = iv)); return m;
  }, []);
  const scById = useMemo(() => {
    const m = {}; D.spacecraft.forEach((sc) => (m[sc.id] = sc)); return m;
  }, []);

  // Масштаб → px/ms (умещаем span в условные 1100px рабочей ширины).
  const scale = SCALES.find((s) => s.id === scaleId);
  const VIEW_W = 1180;
  const pxPerMs = VIEW_W / scale.span;
  const rangeStart = D.RANGE_START;
  const rangeEnd = D.RANGE_END;

  // Фильтрация КА.
  const scByGroup = useMemo(() => {
    const m = {};
    D.spacecraft.forEach((sc) => { (m[sc.groupId] = m[sc.groupId] || []).push(sc); });
    return m;
  }, []);

  const q = search.trim().toLowerCase();
  const matchesSearch = (sc) => !q || sc.name.toLowerCase().includes(q) || sc.short.toLowerCase().includes(q);

  // Счётчики для легенды.
  const counts = useMemo(() => {
    const byType = {};
    D.spacecraft.forEach((sc) => { byType[sc.type] = (byType[sc.type] || 0) + 1; });
    return { byType };
  }, []);

  // Интервалы по КА (с учётом типового фильтра не трогаем — фильтр по типу скрывает строки целиком).
  const ivBySc = useMemo(() => {
    const m = {};
    D.plans.forEach((iv) => { (m[iv.scId] = m[iv.scId] || []).push(iv); });
    return m;
  }, []);

  // Сборка строк таймлайна.
  const rows = useMemo(() => {
    const out = [];
    for (const g of D.GROUP_DEFS) {
      if (!groupShown[g.id]) continue;
      const list = (scByGroup[g.id] || [])
        .filter((sc) => typeFilter[sc.type])
        .filter((sc) => !scHidden.has(sc.id))
        .filter(matchesSearch);
      if (list.length === 0) continue;
      out.push({ kind: "group", group: g, count: list.length });
      if (timelineCollapsed.has(g.id)) continue;
      for (const sc of list) {
        out.push({ kind: "sc", sc, ivs: ivBySc[sc.id] || [] });
      }
    }
    return out;
  }, [groupShown, scHidden, typeFilter, q, timelineCollapsed]);

  // Цепочка родословной выбранного интервала.
  const lineageSet = useMemo(() => {
    if (!selectedIv) return null;
    const lin = lineageOf(selectedIv, byId);
    return new Set(lin.chain);
  }, [selectedIv]);

  const selIv = selectedIv ? byId[selectedIv] : null;
  const selSc = selIv ? scById[selIv.scId] : null;
  const selGroup = selSc ? D.GROUP_DEFS.find((g) => g.id === selSc.groupId) : null;

  const toggleGroup = (id) => setGroupShown((s) => ({ ...s, [id]: !s[id] }));
  const toggleSc = (id) => setScHidden((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const toggleCollapse = (id) => setTimelineCollapsed((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });

  const onPickSc = (id) => {
    setSelectedSc(id);
    // прокрутка к первому интервалу этого КА
    const ivs = ivBySc[id] || [];
    if (ivs.length) { setSelectedIv(null); }
  };

  // Статистика по видимым.
  const stats = useMemo(() => {
    let sc = 0, iv = 0, ov = 0;
    rows.forEach((r) => {
      if (r.kind === "sc") {
        sc++;
        iv += r.ivs.length;
        ov += overlapSegments(r.ivs).length;
      }
    });
    return { sc, iv, ov };
  }, [rows]);

  const allOn = D.GROUP_DEFS.every((g) => groupShown[g.id]) && scHidden.size === 0;
  const showAll = () => { const o = {}; D.GROUP_DEFS.forEach((g) => (o[g.id] = true)); setGroupShown(o); setScHidden(new Set()); };

  return (
    <div style={{ display: "grid", gridTemplateColumns: `268px 1fr ${selIv ? "340px" : "0px"}`, height: "100vh", transition: "grid-template-columns .18s" }}>
      <Sidebar
        groups={D.GROUP_DEFS} scByGroup={scByGroup}
        typeFilter={typeFilter} setTypeFilter={setTypeFilter}
        groupShown={groupShown} toggleGroup={toggleGroup}
        scHidden={scHidden} toggleSc={toggleSc}
        search={search} setSearch={setSearch}
        counts={counts} selectedSc={selectedSc} onPickSc={onPickSc}
      />

      <div style={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
        {/* ТУЛБАР */}
        <div style={{ height: 50, flex: "none", display: "flex", alignItems: "center", gap: 14, padding: "0 16px", borderBottom: "1px solid var(--line)", background: "var(--bg-1)" }}>
          {/* масштаб */}
          <div style={{ display: "flex", gap: 2, background: "var(--bg-0)", borderRadius: 7, padding: 3, border: "1px solid var(--line)" }}>
            {SCALES.map((s) => (
              <button key={s.id} onClick={() => { setScaleId(s.id); setScrollSignal((x) => x + 1); }}
                style={{ padding: "5px 11px", borderRadius: 5, border: "none", fontSize: 11.5, fontWeight: 600, background: scaleId === s.id ? "var(--bg-3)" : "transparent", color: scaleId === s.id ? "var(--ink)" : "var(--ink-3)" }}>{s.label}</button>
            ))}
          </div>

          <button onClick={() => setScrollSignal((x) => x + 1)} style={{ display: "flex", alignItems: "center", gap: 6, padding: "6px 11px", borderRadius: 6, border: "1px solid var(--line)", background: "var(--bg-2)", fontSize: 11.5, fontWeight: 600, color: "var(--now)" }}>
            <span style={{ width: 6, height: 6, borderRadius: 9, background: "var(--now)", boxShadow: "0 0 6px var(--now)" }} />Сейчас
          </button>

          <div style={{ width: 1, height: 22, background: "var(--line)" }} />
          <WorksLegend />

          <div style={{ flex: 1 }} />

          {/* статистика */}
          <div style={{ display: "flex", gap: 16, alignItems: "center" }}>
            <Stat label="АППАРАТОВ" v={stats.sc} />
            <Stat label="ПЛАНОВ" v={stats.iv} />
            <Stat label="ПЕРЕСЕЧЕНИЙ" v={stats.ov} accent={stats.ov > 0 ? "var(--now)" : null} />
          </div>

          {!allOn && (
            <button onClick={showAll} style={{ padding: "6px 11px", borderRadius: 6, border: "1px solid var(--line)", background: "var(--bg-2)", fontSize: 11.5, color: "var(--ink-1)" }}>Показать все</button>
          )}
        </div>

        {rows.length === 0 ? (
          <div style={{ flex: 1, display: "grid", placeItems: "center", color: "var(--ink-3)", fontSize: 13 }}>
            Нет аппаратов по текущим фильтрам.
          </div>
        ) : (
          <div style={{ flex: 1, minHeight: 0 }} onClick={() => {}}>
            <Timeline
              rows={rows} pxPerMs={pxPerMs} rangeStart={rangeStart} rangeEnd={rangeEnd}
              now={D.NOW} selectedIv={selectedIv} onSelectIv={setSelectedIv}
              lineageSet={lineageSet} byId={byId} scrollSignal={scrollSignal}
              timelineCollapsed={timelineCollapsed} toggleCollapse={toggleCollapse}
            />
          </div>
        )}
      </div>

      <Details iv={selIv} sc={selSc} group={selGroup} byId={byId} onSelectIv={setSelectedIv} onClose={() => setSelectedIv(null)} />
    </div>
  );
}

function WorksLegend() {
  const items = [
    { k: "shoot", label: "Съёмка", stripes: true },
    { k: "downlink", label: "Сброс", fill: "var(--accent)" },
    { k: "calib", label: "Калибровка", fill: "oklch(0.78 0.02 200)" },
    { k: "service", label: "Служебная", dashed: true },
  ];
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
      <span className="mono" style={{ fontSize: 8.5, color: "var(--ink-3)", letterSpacing: ".08em" }}>РАБОТЫ:</span>
      {items.map((it) => (
        <div key={it.k} style={{ display: "flex", alignItems: "center", gap: 5 }}>
          <span style={{
            width: 11, height: 9, borderRadius: 2, flex: "none",
            background: it.stripes
              ? "linear-gradient(90deg, var(--t-optical) 0 33%, var(--t-radar) 33% 66%, var(--t-combo) 66% 100%)"
              : it.dashed ? "transparent" : it.fill,
            border: it.dashed ? "1px dashed var(--ink-3)" : "none",
          }} />
          <span style={{ fontSize: 10.5, color: "var(--ink-2)" }}>{it.label}</span>
        </div>
      ))}
    </div>
  );
}

function Stat({ label, v, accent }) {  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", lineHeight: 1.1 }}>
      <span className="mono tnum" style={{ fontSize: 15, fontWeight: 600, color: accent || "var(--ink)" }}>{v}</span>
      <span className="mono" style={{ fontSize: 8, color: "var(--ink-3)", letterSpacing: ".08em" }}>{label}</span>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
