// tree-page.jsx — «Дерево задач»: ієрархія Об'єкт → Етап → Задача → Підзадача
// з розгортанням/згортанням, агрегацією прогресу, фільтрами та інлайн-діями.

function TreePage({ tasks, onOpenTask, onToggle, onTaskPatch, role }) {
  const { useState, useMemo, useCallback } = React;
  const objects = window.DATA.OBJECTS;
  const team = window.DATA.TEAM;
  const allStages = [...window.DATA.STAGES, ...(window.DATA.CORRECTION_STAGES || [])];
  const stageById = useMemo(() => {
    const m = {}; allStages.forEach(s => m[s.id] = s); return m;
  }, []);

  // Поточний користувач (для фільтра «Тільки мої»)
  const meId = (window.API && window.API.mode === "live" && window.API.user && window.API.user.teamId)
    || "ok";

  // ── Фільтри ─────────────────────────────────────────────
  const [filterAssignee, setFilterAssignee] = useState("all"); // all | mine | <id>
  const [filterStatus, setFilterStatus] = useState("all");     // all | todo | live | late | done
  const [query, setQuery] = useState("");

  // ── Стан розгорнутих гілок (persist) ────────────────────
  const STORE_KEY = "erp_tree_expanded_v1";
  const [expanded, setExpanded] = useState(() => {
    try {
      const raw = localStorage.getItem(STORE_KEY);
      if (raw) return JSON.parse(raw);
    } catch (e) {}
    // дефолт: усі об'єкти й етапи розгорнуті, задачі згорнуті
    const init = {};
    objects.forEach(o => { init["obj:" + o.id] = true; });
    init["obj:admin"] = true;
    return init;
  });
  const persist = (next) => {
    setExpanded(next);
    try { localStorage.setItem(STORE_KEY, JSON.stringify(next)); } catch (e) {}
  };
  const isOpen = (key, def) => key in expanded ? expanded[key] : !!def;
  const toggleKey = (key, def) => {
    const cur = key in expanded ? expanded[key] : !!def;
    persist({ ...expanded, [key]: !cur });
  };

  // ── Фільтрація задач ────────────────────────────────────
  const q = query.trim().toLowerCase();
  const matchTask = (t) => {
    if (filterAssignee === "mine" && t.assignee !== meId) return false;
    if (filterAssignee !== "all" && filterAssignee !== "mine" && t.assignee !== filterAssignee) return false;
    if (filterStatus !== "all" && t.status !== filterStatus) return false;
    if (q) {
      const obj = window.getObject(t.obj);
      const hay = (t.title + " " + (obj?.code || "") + " " + (obj?.name || "") + " " + (t.section || "")).toLowerCase();
      if (!hay.includes(q)) return false;
    }
    return true;
  };
  const filtered = tasks.filter(matchTask);

  // ── Агрегація ───────────────────────────────────────────
  const agg = (list) => {
    const a = { total: list.length, done: 0, live: 0, late: 0, todo: 0 };
    list.forEach(t => { a[t.status] = (a[t.status] || 0) + 1; });
    a.pct = a.total ? Math.round(a.done / a.total * 100) : 0;
    return a;
  };

  // ── Групування: об'єкт → етап → задачі ──────────────────
  const groups = useMemo(() => {
    const byObj = {};
    filtered.forEach(t => {
      const key = t.obj || "admin";
      (byObj[key] = byObj[key] || []).push(t);
    });
    // порядок об'єктів як у DATA, адмін — в кінці
    const ordered = objects
      .filter(o => byObj[o.id])
      .map(o => ({ obj: o, tasks: byObj[o.id] }));
    if (byObj["admin"]) {
      ordered.push({
        obj: { id: "admin", code: "АДМ", name: "Поза об'єктами", admin: true },
        tasks: byObj["admin"],
      });
    }
    return ordered;
  }, [filtered, objects]);

  const totalAgg = agg(filtered);

  // ── Розгорнути / згорнути все ───────────────────────────
  const setAll = (open) => {
    const next = {};
    groups.forEach(g => {
      next["obj:" + g.obj.id] = open;
      const stages = [...new Set(g.tasks.map(t => t.stage || "admin"))];
      stages.forEach(sid => { next["stage:" + g.obj.id + ":" + sid] = open; });
      if (open) g.tasks.forEach(t => {
        if ((t.subtasks || []).length) next["task:" + t.id] = true;
      });
    });
    persist(next);
  };

  // ── Інлайн: тогл підзадачі ──────────────────────────────
  const toggleSub = (taskId, subId) => {
    if (!onTaskPatch) return;
    onTaskPatch(taskId, (x) => ({
      ...x,
      subtasks: (x.subtasks || []).map(s =>
        s.id === subId ? { ...s, status: s.status === "done" ? "todo" : "done" } : s),
    }));
  };

  // стейт-пілюлі
  const statusPills = [
    { id: "all",  label: "Усі" },
    { id: "todo", label: "До виконання" },
    { id: "live", label: "У роботі" },
    { id: "late", label: "Прострочено" },
    { id: "done", label: "Виконано" },
  ];

  const activeFilter = filterAssignee !== "all" || filterStatus !== "all" || q;

  return (
    <div className="page tree-page">
      <TreeStyles />

      <div className="page-head">
        <h1 className="page-h1">Дерево задач</h1>
        <div className="page-sub">
          <span>{groups.length} {window.plural(groups.length, "об'єкт", "об'єкти", "об'єктів")}</span>
          <span className="dot"></span>
          <span>{totalAgg.total} {window.plural(totalAgg.total, "задача", "задачі", "задач")}</span>
          {totalAgg.late > 0 && <>
            <span className="dot"></span>
            <span style={{ color: "var(--late)" }}>{totalAgg.late} прострочено</span>
          </>}
          <span className="dot"></span>
          <span>{totalAgg.pct}% виконано</span>
        </div>
      </div>

      {/* Тулбар */}
      <div className="tree-toolbar">
        <div className="search tree-search">
          <window.Icon.Search />
          <input
            placeholder="Знайти задачу, об'єкт, розділ…"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
          />
          {query && <button className="tree-search-x" onClick={() => setQuery("")}><window.Icon.X /></button>}
        </div>

        <div className="tree-tb-spacer"></div>

        <div className="tree-expand-btns">
          <button className="btn btn-sm" onClick={() => setAll(true)}>Розгорнути все</button>
          <button className="btn btn-sm" onClick={() => setAll(false)}>Згорнути все</button>
        </div>
      </div>

      <div className="tree-toolbar tree-toolbar-2">
        <div className="filter-pill" role="tablist">
          <button className={`filter-pill-item ${filterAssignee === "all" ? "is-active" : ""}`} onClick={() => setFilterAssignee("all")}>Уся команда</button>
          <button className={`filter-pill-item ${filterAssignee === "mine" ? "is-active" : ""}`} onClick={() => setFilterAssignee("mine")}>Тільки мої</button>
          {team.filter(p => p.employment !== "contractor").map(p => (
            <button
              key={p.id}
              className={`filter-pill-item ${filterAssignee === p.id ? "is-active" : ""}`}
              onClick={() => setFilterAssignee(p.id)}
              title={p.name}
            >
              <span className="av" style={{ width: 22, height: 22, fontSize: 9.5, border: "none" }}>{p.initials[0]}</span>
              {p.initials}
            </button>
          ))}
        </div>

        <div className="tree-tb-spacer"></div>

        <div className="filter-pill" role="tablist">
          {statusPills.map(s => (
            <button
              key={s.id}
              className={`filter-pill-item ${filterStatus === s.id ? "is-active" : ""}`}
              onClick={() => setFilterStatus(s.id)}
            >{s.label}</button>
          ))}
        </div>
      </div>

      {/* Дерево */}
      <div className="tree">
        {groups.length === 0 && (
          <div className="empty" style={{ padding: "40px 0" }}>
            {activeFilter ? "За цим фільтром задач немає." : "Задач ще немає."}
          </div>
        )}

        {groups.map(g => {
          const objKey = "obj:" + g.obj.id;
          const objOpen = isOpen(objKey, true);
          const objAgg = agg(g.tasks);

          // етапи цього об'єкта в порядку allStages, admin — як псевдоетап
          const stageIds = [...new Set(g.tasks.map(t => t.stage || "admin"))];
          const orderedStages = allStages
            .map(s => s.id)
            .filter(id => stageIds.includes(id));
          if (stageIds.includes("admin")) orderedStages.push("admin");

          return (
            <div className="tree-obj" key={g.obj.id}>
              {/* ── Об'єкт ── */}
              <div className={`tr-node tr-obj ${objOpen ? "is-open" : ""}`} onClick={() => toggleKey(objKey, true)}>
                <Chevron open={objOpen} />
                <span className={`tr-obj-code ${g.obj.admin ? "is-admin" : ""}`}>{g.obj.code}</span>
                <span className="tr-obj-name">{g.obj.name}</span>
                {g.obj.deadline && <span className="tr-obj-dl">Дедлайн {g.obj.deadline}</span>}
                <span className="tr-flex"></span>
                {objAgg.late > 0 && <span className="tr-badge is-late">{objAgg.late} прострочено</span>}
                {objAgg.live > 0 && <span className="tr-badge is-live">{objAgg.live} у роботі</span>}
                <span className="tr-count">{objAgg.done}/{objAgg.total}</span>
                <MiniBar pct={objAgg.pct} />
              </div>

              {/* ── Етапи ── */}
              {objOpen && (
                <div className="tr-children tr-children-stage">
                  {orderedStages.map(sid => {
                    const stage = sid === "admin"
                      ? { id: "admin", name: "Адміністративні", short: "Адмін" }
                      : stageById[sid];
                    const stageTasks = g.tasks.filter(t => (t.stage || "admin") === sid);
                    const stageKey = "stage:" + g.obj.id + ":" + sid;
                    const stageOpen = isOpen(stageKey, true);
                    const sAgg = agg(stageTasks);
                    const color = stageColor(sid);
                    return (
                      <div className="tree-stage" key={sid}>
                        <div className={`tr-node tr-stage ${stageOpen ? "is-open" : ""}`} onClick={() => toggleKey(stageKey, true)}>
                          <Chevron open={stageOpen} small />
                          <span className="tr-stage-dot" style={{ background: color }}></span>
                          <span className="tr-stage-name">{stage?.name || sid}</span>
                          <span className="tr-flex"></span>
                          {sAgg.late > 0 && <span className="tr-dot-late" title={sAgg.late + " прострочено"}></span>}
                          <span className="tr-count tr-count-sm">{sAgg.done}/{sAgg.total}</span>
                          <MiniBar pct={sAgg.pct} small color={color} />
                        </div>

                        {/* ── Задачі ── */}
                        {stageOpen && (
                          <div className="tr-children tr-children-task">
                            {stageTasks.map(t => (
                              <TreeTask
                                key={t.id}
                                task={t}
                                open={isOpen("task:" + t.id, false)}
                                onToggleOpen={() => toggleKey("task:" + t.id, false)}
                                onToggleDone={() => onToggle(t)}
                                onOpen={() => onOpenTask(t)}
                                onToggleSub={(sid2) => toggleSub(t.id, sid2)}
                              />
                            ))}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── Вузол задачі ──────────────────────────────────────────
function TreeTask({ task, open, onToggleOpen, onToggleDone, onOpen, onToggleSub }) {
  const team = window.getTeam(task.assignee);
  const subs = task.subtasks || [];
  const subDone = subs.filter(s => s.status === "done").length;
  const isDone = task.status === "done";
  const isLive = task.status === "live";
  const isLate = task.status === "late";
  const hasSubs = subs.length > 0;

  return (
    <div className="tree-task">
      <div className={`tr-node tr-task ${isDone ? "is-done" : ""} ${isLate ? "is-late" : ""} ${isLive ? "is-live" : ""}`}>
        {hasSubs
          ? <button className="tr-task-chev" onClick={onToggleOpen} aria-label="Розгорнути підзадачі"><Chevron open={open} small /></button>
          : <span className="tr-task-chev tr-leaf-dot"></span>}

        <button
          className="task-check tr-check"
          onClick={(e) => { e.stopPropagation(); onToggleDone(); }}
          aria-label={isDone ? "Зняти позначку" : "Виконано"}
        ><window.Icon.Check /></button>

        <span className="tr-task-title" onClick={onOpen}>{task.title}</span>

        <span className="tr-flex"></span>

        {task.section && <span className="tr-sec">{task.section}</span>}
        {hasSubs && (
          <span className={`tr-subcount ${subDone === subs.length ? "is-full" : ""}`}>
            {subDone}/{subs.length}
          </span>
        )}
        {isLate && <span className="tr-chip is-late">Прострочено</span>}
        {isLive && <span className="tr-chip is-live">У роботі</span>}
        {!isDone && task.est && <span className="tr-est">{task.est}</span>}
        {team && <span className="task-assignee tr-av" title={team.name}>{team.initials}</span>}
      </div>

      {/* ── Підзадачі ── */}
      {open && hasSubs && (
        <div className="tr-children tr-children-sub">
          {subs.map(s => {
            const sp = s.assignee ? window.getTeam(s.assignee) : null;
            const sd = s.status === "done";
            return (
              <div className={`tr-node tr-sub ${sd ? "is-done" : ""}`} key={s.id}>
                <span className="tr-task-chev tr-leaf-dot tr-leaf-deep"></span>
                <button
                  className="st-check tr-sub-check"
                  onClick={() => onToggleSub(s.id)}
                  title={sd ? "Зняти позначку" : "Позначити виконаним"}
                >{sd && <window.Icon.Check />}</button>
                <span className="tr-sub-title">{s.title}</span>
                <span className="tr-flex"></span>
                {s.due && <span className="tr-sub-due">{s.due}</span>}
                {sp && <span className="task-assignee tr-av tr-av-sm" title={sp.name}>{sp.initials}</span>}
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ── Дрібнички ─────────────────────────────────────────────
function Chevron({ open, small }) {
  return (
    <svg
      className={`tr-chevron ${open ? "is-open" : ""} ${small ? "is-sm" : ""}`}
      viewBox="0 0 12 12" width="12" height="12" fill="none"
    >
      <path d="M4 2L8 6L4 10" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function MiniBar({ pct, small, color }) {
  return (
    <div className={`tr-bar ${small ? "is-sm" : ""}`}>
      <div className="tr-bar-track">
        <div className="tr-bar-fill" style={{ width: pct + "%", background: color || "var(--accent)" }}></div>
      </div>
      <span className="tr-bar-pct">{pct}%</span>
    </div>
  );
}

function stageColor(sid) {
  const base = sid.replace(/^c-/, "");
  const map = {
    project:     "#068B49",
    estimate:    "#015B76",
    expertise:   "oklch(0.66 0.13 65)",
    edessb:      "oklch(0.58 0.12 300)",
    supervision: "oklch(0.6 0.11 250)",
    admin:       "var(--ink-3)",
  };
  return map[base] || "var(--ink-3)";
}

// ── Стилі (інжектуються разом зі сторінкою) ───────────────
function TreeStyles() {
  return (
    <style>{`
      .tree-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
      .tree-toolbar-2 { margin-bottom: 18px; }
      .tree-tb-spacer { flex: 1 1 auto; }
      .tree-search { min-width: 280px; flex: 0 1 360px; }
      .tree-search input { width: 100%; }
      .tree-search-x { background: none; border: none; color: var(--ink-3); cursor: pointer; display: flex; padding: 2px; }
      .tree-search-x:hover { color: var(--ink); }
      .tree-expand-btns { display: flex; gap: 8px; }

      .tree { display: flex; flex-direction: column; gap: 10px; }
      .tree-obj { background: var(--bg-elev); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }

      /* Базовий вузол */
      .tr-node { display: flex; align-items: center; gap: 10px; min-height: calc(40px * var(--dens, 1)); padding: 0 14px; }
      .tr-flex { flex: 1 1 auto; }

      /* Об'єкт */
      .tr-obj { cursor: pointer; min-height: calc(52px * var(--dens, 1)); border-bottom: 1px solid transparent; user-select: none; }
      .tr-obj.is-open { border-bottom-color: var(--line); }
      .tr-obj:hover { background: var(--bg-hover); }
      .tr-obj-code { font-family: var(--mono, ui-monospace, monospace); font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
        color: var(--accent-ink); background: var(--accent-soft); padding: 3px 8px; border-radius: 6px; white-space: nowrap; }
      .tr-obj-code.is-admin { color: var(--ink-2); background: var(--bg-sunken); }
      .tr-obj-name { font-size: 14px; font-weight: 650; color: var(--ink); }
      .tr-obj-dl { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; }

      /* Гілки + напрямні лінії */
      .tr-children { position: relative; }
      .tr-children-stage { padding-left: 0; }
      .tree-stage { position: relative; }

      /* Етап */
      .tr-stage { cursor: pointer; padding-left: 34px; min-height: calc(42px * var(--dens, 1));
        border-top: 1px solid var(--line); user-select: none; }
      .tree-stage:first-child .tr-stage { border-top: none; }
      .tr-stage:hover { background: var(--bg-hover); }
      .tr-stage-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
      .tr-stage-name { font-size: 13px; font-weight: 600; color: var(--ink); }

      /* Задачі: відступ + вертикальна напрямна */
      .tr-children-task { padding-left: 34px; }
      .tree-task { position: relative; }
      .tr-task { padding-left: 24px; min-height: calc(40px * var(--dens, 1)); border-top: 1px solid var(--line);
        position: relative; }
      .tree-task:first-child > .tr-task { border-top: none; }
      .tr-task:hover { background: var(--bg-hover); }
      .tr-task.is-late { box-shadow: inset 3px 0 0 var(--late); }
      .tr-task.is-live { box-shadow: inset 3px 0 0 var(--c-green); }
      .tr-task-chev { background: none; border: none; padding: 0; display: flex; align-items: center; justify-content: center;
        width: 16px; height: 16px; color: var(--ink-3); cursor: pointer; flex: none; }
      .tr-task-chev:hover { color: var(--ink); }
      .tr-leaf-dot { width: 16px; }
      .tr-leaf-dot::before { content: ""; width: 4px; height: 4px; border-radius: 50%; background: var(--ink-4); margin: auto; }
      .tr-leaf-deep::before { background: var(--line-strong); }
      .tr-check { width: 18px; height: 18px; flex: none; }
      .tr-task-title { font-size: 13px; color: var(--ink); cursor: pointer; }
      .tr-task-title:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; }
      .tr-task.is-done .tr-task-title { color: var(--ink-3); text-decoration: line-through; }

      .tr-sec { font-size: 10px; font-weight: 700; letter-spacing: 0.03em; color: var(--ink-3);
        border: 1px solid var(--line-strong); border-radius: 5px; padding: 1px 6px; white-space: nowrap; }
      .tr-subcount { font-size: 11px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums;
        background: var(--bg-sunken); border-radius: 5px; padding: 1px 7px; }
      .tr-subcount.is-full { color: var(--accent-ink); background: var(--accent-soft); }
      .tr-est { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }

      /* Чипи статусу */
      .tr-chip { font-size: 10.5px; font-weight: 700; padding: 2px 8px; border-radius: 20px; white-space: nowrap; }
      .tr-chip.is-late { color: var(--late); background: var(--late-bg); }
      .tr-chip.is-live { color: var(--c-green-deep); background: var(--live-bg); }

      .tr-badge { font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 20px; white-space: nowrap; }
      .tr-badge.is-late { color: var(--late); background: var(--late-bg); }
      .tr-badge.is-live { color: var(--c-green-deep); background: var(--live-bg); }
      .tr-dot-late { width: 7px; height: 7px; border-radius: 50%; background: var(--late); flex: none; }

      .tr-count { font-size: 12px; font-weight: 700; color: var(--ink-2); font-variant-numeric: tabular-nums; min-width: 38px; text-align: right; }
      .tr-count-sm { font-size: 11.5px; font-weight: 600; min-width: 34px; }

      /* Аватари */
      .tr-av { width: 26px; height: 26px; font-size: 10px; flex: none; }
      .tr-av-sm { width: 22px; height: 22px; font-size: 9px; }

      /* Підзадачі */
      .tr-children-sub { padding-left: 24px; }
      .tr-sub { padding-left: 24px; min-height: calc(34px * var(--dens, 1)); border-top: 1px dashed var(--line); }
      .tr-sub:hover { background: var(--bg-hover); }
      .tr-sub-check { width: 16px; height: 16px; flex: none; border-radius: 5px; border: 1.5px solid var(--line-strong);
        background: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #fff; }
      .tr-sub.is-done .tr-sub-check { background: var(--c-green); border-color: var(--c-green); }
      .tr-sub-title { font-size: 12.5px; color: var(--ink-2); }
      .tr-sub.is-done .tr-sub-title { color: var(--ink-3); text-decoration: line-through; }
      .tr-sub-due { font-size: 11px; color: var(--ink-3); white-space: nowrap; }

      /* Шеврон */
      .tr-chevron { color: var(--ink-3); flex: none; transition: transform 0.15s ease; }
      .tr-chevron.is-open { transform: rotate(90deg); }
      .tr-chevron.is-sm { width: 11px; height: 11px; }

      /* Міні-бар прогресу */
      .tr-bar { display: flex; align-items: center; gap: 8px; width: 130px; flex: none; }
      .tr-bar.is-sm { width: 108px; }
      .tr-bar-track { flex: 1 1 auto; height: 6px; background: var(--bg-sunken); border-radius: 4px; overflow: hidden; }
      .tr-bar-fill { height: 100%; border-radius: 4px; transition: width 0.2s ease; }
      .tr-bar-pct { font-size: 11px; font-weight: 700; color: var(--ink-2); font-variant-numeric: tabular-nums; min-width: 30px; text-align: right; }

      @media (max-width: 880px) {
        .tr-bar { width: 70px; }
        .tr-obj-dl, .tr-est, .tr-sec { display: none; }
      }
    `}</style>
  );
}

window.TreePage = TreePage;
