/* executor-home.jsx — главная исполнителя (KSH-520). Роман, 05.11.2026: на главной только важные процессы по всем объектам мастера,
   остальное — внутри проекта. Собрана из блоков кабинета клиента и пульта прораба (LKW из lk-widgets.jsx, внутри .lw-scope):
   «Новые наряды» (ExecOrderOffers, KSH-519) → серая карточка денег (FactsBand) → «Сейчас важно» (NowCards) → «Мои задачи» (KSH-528: таск-менеджер — списком по сроку
   или графиком недели со смежными работами) → плитки объектов (ObjTile) → «Отпуск и больничный».
   Данные — ExecutorViews (executor-views.js), ничего не пишет, кроме отсутствия приходящего мастера (StaffStore.away, KSH-524).
   Exports: window.ExecHome */
(function () {
  const W = () => window.LKW;
  const rub = (n) => (Math.round(+n || 0)).toLocaleString('ru-RU') + ' ₽';
  const dm = (s) => (s ? s.slice(8, 10) + '.' + s.slice(5, 7) : '');
  const plural = (n, a, b, c) => { const m = Math.abs(n) % 100, k = m % 10; return m > 10 && m < 20 ? c : k > 1 && k < 5 ? b : k === 1 ? a : c; };
  const NOWK = { returned: 'Возврат на доработку', late: 'Просрочено', today: 'Работа на сегодня', price: 'Цена на согласовании' };

  function useTick() {
    const [, set] = React.useState(0);
    React.useEffect(() => {
      const bump = () => set((x) => x + 1);
      const un = window.ProjectStore && window.ProjectStore.subscribe ? window.ProjectStore.subscribe(bump) : null;
      const evs = ['obitel:exec-prices', 'obitel:staff', 'obitel:sync', 'storage'];
      evs.forEach((e) => window.addEventListener(e, bump));
      return () => { if (un) un(); evs.forEach((e) => window.removeEventListener(e, bump)); };
    }, []);
  }
  // ссылка на задание и на смету проекта: личность (?user=, ?t=) переносится
  function href(page, extra) {
    const cur = new URLSearchParams(window.location.search); const q = new URLSearchParams();
    ['user', 't'].forEach((k) => { if (cur.get(k)) q.set(k, cur.get(k)); });
    Object.entries(extra || {}).forEach(([k, v]) => q.set(k, v));
    return page + '?' + q.toString();
  }
  const go = (u) => { window.location.href = u; };
  const taskUrl = (taskId) => href('executor-task.html', { task: taskId });
  const projUrl = (pid) => href('executor-estimate.html', { project: pid });

  function nowRows(list, onProject) {
    const openProj = (pid) => (onProject ? onProject(pid) : go(projUrl(pid)));
    return list.slice(0, 6).map((x) => ({
      key: x.kind + x.pid + (x.taskId || ''), kindL: NOWK[x.kind], late: x.kind === 'late' || x.kind === 'returned',
      right: x.kind === 'late' ? 'на ' + x.overdueDays + ' ' + plural(x.overdueDays, 'день', 'дня', 'дней') : x.dueToday ? 'сегодня' : '',
      title: x.title, sub: x.obj + (x.sub ? ' · ' + x.sub : ''),
      act: x.kind === 'price' ? { text: 'Смета', onClick: () => openProj(x.pid) } : { text: x.kind === 'returned' ? 'Исправить' : 'Открыть', onClick: () => go(taskUrl(x.taskId)) },
    }));
  }

  function W_Ic({ n }) { const L = W(); return L ? <L.Ic n={n} s={14} /> : null; }

  /* «Мой график» (KSH-528): неделя по дням — свои работы и смежные (перед вами, после вас, ваша специальность), 4 недели вперёд;
     ниже — мои этапы и готовность фронта: кто передо мной, кто ждёт меня, что мешает зайти. Тот же календарь, что у прораба (LKW.WeekW) */
  const NB_KINDS = new Set(['before', 'review', 'late']); // про работу перед мной уже сказано в строке «Перед вами»
  const FRONT_CLS = { ready: 'is-ready', wait: 'is-wait', late: 'is-late', go: 'is-go', done: 'is-done' };
  const NB_ST = (o) => o.status === 'done' ? 'сдано' : o.status === 'review' ? 'на приёмке' : o.state === 'late' ? 'задерживается' : 'до ' + dm(o.end);
  /* «Мой график» на модели прораба (Роман, 07.11): объекты → фазы → этапы, в этапе мои работы и соседние (пунктиром),
     шкала дни / недели / месяцы, события объекта. Ниже — мои этапы и готовность фронта */
  function Schedule({ me, onProject }) {
    const V = window.ExecutorViews; const L = W();
    const t0 = new Date().toISOString().slice(0, 10);
    const [scale, setScale] = React.useState('day');
    const sc = V.schedule(me, t0, t0);
    const gt = V.gantt ? V.gantt(me, t0) : { rows: [] };
    const empty = !gt.rows.length && !sc.blocks.length;
    return (
      <div className="xh-sch">
        <div className="xh-gh"><p className="lab xh-note">Ваши работы и соседние: кто работает в тех же комнатах до и после вас и кто ещё на объекте по вашей специальности. Чужие работы — пунктиром.</p>
          {gt.rows.length ? <L.ScaleTabs scale={scale} onScale={setScale} /> : null}</div>
        {empty ? <div className="empty">Работ пока нет.</div> : <React.Fragment>
          {gt.rows.length ? <L.GanttW g={gt} detail autoOpen head="Объект, фазы и этапы" scale={scale} onScale={setScale}
            onWork={(wk) => { if (wk.mine) go(taskUrl(wk.id)); }} onRow={(r) => (onProject ? onProject(r.id) : go(projUrl(r.id)))} /> : null}
          {sc.blocks.length ? <React.Fragment>
            <h3 className="xh-h3">Мои этапы и готовность фронта</h3>
            <div className="xh-fr-l">{sc.blocks.map((b) => (
              <a key={b.pid + b.stageId} className="xh-fr" href={taskUrl(b.taskId)}>
                <span className="xh-fr-a"><span className="t">{b.stage || b.works[0]}</span>
                  <span className="lab">{b.obj} · {dm(b.start)}{b.end && b.end !== b.start ? '–' + dm(b.end) : ''} · {b.works.length} {plural(b.works.length, 'работа', 'работы', 'работ')}</span></span>
                <span className="xh-fr-b">
                  {b.front.k === 'go' || (b.front.k === 'late' && !b.front.waits.length) ? null : b.before.length ? <span className="lab"><b>Перед вами:</b> {b.before.map((o) => '«' + o.title + '»' + (o.who ? ', ' + o.who : '') + ' — ' + NB_ST(o)).join('; ')}</span> : <span className="lab"><b>Перед вами:</b> никого, вы первый в этих комнатах</span>}
                  {b.after.length ? <span className="lab"><b>После вас:</b> {b.after.map((o) => '«' + o.title + '»' + (o.who ? ', ' + o.who : '') + ' — с ' + dm(o.start)).join('; ')}</span> : null}
                  {(() => { const more = b.front.waits.slice(1).filter((x) => !NB_KINDS.has(x.k)); return more.length ? <span className="lab">Ещё: {more.map((x) => x.l).join('; ')}</span> : null; })()}
                </span>
                <span className={'xh-chip ' + FRONT_CLS[b.front.k]}>{b.late ? 'Просрочено на ' + b.late + ' дн' : b.front.l}</span>
              </a>))}</div>
          </React.Fragment> : null}
        </React.Fragment>}
      </div>);
  }

  /* «Мои задачи» (KSH-528, Роман 07.11.2026: «мой график — то же самое, давай в виде таск-менеджера»): всё, что сейчас на мне по всем
     объектам, — списком по сроку или графиком. Вкладка «От меня» (что я вернул или отправил другим, KSH-530) появится сама,
     когда подключат TaskViews.outbox */
  function MyTasks({ me, onProject }) {
    const L = W(), T = window.TaskViews;
    if (!T) return null;
    const t0 = new Date().toISOString().slice(0, 10);
    // вид «Канбан» (KSH-533): колонки по статусам; «От меня» — переносы дат и мои цены, решённое видно 3 дня
    const tabs = [{ id: 'in', label: 'Мне сделать', rows: T.inbox('executor', me, t0), empty: 'Сейчас на вас ничего нет.', columns: T.IN_COLUMNS, colOf: T.inCol }];
    if (T.outbox) { try { tabs.push({ id: 'out', label: 'От меня', rows: T.outbox({ role: 'executor', id: me }) || [], empty: 'Вы ничего не отправляли на доработку.',
      boardRows: T.outbox({ role: 'executor', id: me }, t0, { closed: true }) || [], columns: T.OUT_COLUMNS, colOf: T.outCol }); } catch (e) { /* источник не готов */ } }
    const openRow = (r) => { if (!r.href) return; const [pg, q] = r.href.split('?'); go(href(pg, Object.fromEntries(new URLSearchParams(q || '')))); };
    return (
      <section className="cv-w xh-tm" aria-label="Мои задачи">
        <L.TaskList title="Мои задачи" tabs={tabs} t0={t0} onOpen={openRow} views={[{ id: 'cal', label: 'График', render: () => <Schedule me={me} onProject={onProject} /> }]} />
      </section>);
  }

  /* отпуск и больничный: приходящий мастер ставит себе сам; штатному ставит прораб или руководитель — здесь только видно */
  function Away({ me }) {
    const S = window.StaffStore;
    const Aw = S && S.away;
    const [open, setOpen] = React.useState(false);
    const [f, setF] = React.useState({ kind: 'vacation', from: '', to: '', note: '' });
    const [err, setErr] = React.useState('');
    if (!Aw) return null;
    const staff = S.get ? S.get(me) : null;
    const self = !(staff && staff.kind !== 'guest');
    const t0 = new Date().toISOString().slice(0, 10);
    const list = Aw.list(me).filter((x) => !x.to || x.to >= t0);
    const by = { role: 'executor', id: me, name: (staff && staff.name) || '' };
    const save = () => { try { Aw.add(me, f, by); setOpen(false); setF({ kind: 'vacation', from: '', to: '', note: '' }); setErr(''); } catch (e) { setErr(e.message); } };
    const del = (id) => { try { Aw.remove(id, by); setErr(''); } catch (e) { setErr(e.message); } };
    return (
      <section className="cv-w xh-away" aria-label="Отпуск и больничный">
        <div className="xh-wh"><h2 className="xh-h2">Отпуск и больничный</h2>
          {self && !open ? <button type="button" className="lw-btn-l" onClick={() => setOpen(true)}>Добавить</button> : null}</div>
        <p className="lab xh-note">{self ? 'В эти дни прораб не выдаст вам новый наряд. Больничный можно поставить без даты выхода.' : 'Отпуск и больничный штатного мастера ставит прораб или руководитель. Здесь видно, что стоит в графике.'}</p>
        {list.length ? list.map((x) => (
          <div key={x.id} className="xh-arow"><span className="t">{x.l}</span><span className="lab">{dm(x.from)}{x.to ? ' — ' + dm(x.to) : ', без даты выхода'}{x.note ? ' · ' + x.note : ''}</span>
            {self ? <button type="button" className="cv-arrow-btn" onClick={() => del(x.id)}>Убрать</button> : null}</div>))
          : !open ? <div className="lab">Отсутствий не запланировано.</div> : null}
        {open && <div className="xh-aform">
          <div className="cv-ctabs">{Object.entries(Aw.KINDS).map(([k, l]) => <button key={k} type="button" className={f.kind === k ? 'on' : ''} onClick={() => setF({ ...f, kind: k })}>{l}</button>)}</div>
          <div className="xh-adates">
            <label><span className="lab">С</span><input type="date" value={f.from} onChange={(e) => setF({ ...f, from: e.target.value })} /></label>
            <label><span className="lab">{f.kind === 'sick' ? 'По (можно пусто)' : 'По'}</span><input type="date" value={f.to} onChange={(e) => setF({ ...f, to: e.target.value })} /></label>
          </div>
          <input className="xh-anote" placeholder="Комментарий прорабу (необязательно)" value={f.note} onChange={(e) => setF({ ...f, note: e.target.value })} />
          <div className="xh-abtn"><button type="button" className="lw-btn-l" onClick={() => { setOpen(false); setErr(''); }}>Отмена</button><button type="button" className="lw-btn-k" onClick={save}>Сохранить</button></div>
        </div>}
        {err && <p className="xh-err">{err}</p>}
      </section>);
  }

  /* новый кабинет (executor-v2, KSH-521): onProject открывает окно проекта вместо страницы сметы, orders — свой блок «Новые наряды»
     по всем объектам, extra — блоки кабинета перед «Отпуском» (чаты, заработок) */
  function ExecHome({ me, onProject, orders, extra }) {
    useTick();
    const L = W(), V = window.ExecutorViews;
    if (!L || !V || !me) return null;
    const m = V.money(me);
    const now = V.now(me);
    const tiles = V.tiles(me);
    return (
      <div className="lw-scope xh">
        {orders !== undefined ? orders : window.ExecOrderOffers && <window.ExecOrderOffers />}
        <L.FactsBand label="Мои деньги" facts={[
          { v: rub(m.earned), lab: 'Заработано · ' + m.accepted + ' ' + plural(m.accepted, 'работа принята', 'работы приняты', 'работ принято') },
          { v: rub(m.pay), lab: 'К выплате' },
          { v: m.hold ? rub(m.hold) : '—', lab: 'Удержано' },
          { v: rub(m.total), lab: 'Всего по нарядам · ' + m.works + ' ' + plural(m.works, 'работа', 'работы', 'работ') },
        ]} />
        {now.length ? <React.Fragment><h2 className="xh-h2 xh-sec">Сейчас важно</h2><L.NowCards rows={nowRows(now, onProject)} /></React.Fragment> : null}
        <MyTasks me={me} onProject={onProject} />
        {tiles.length ? <React.Fragment>
          <h2 className="xh-h2 xh-sec">Мои объекты</h2>
          <div className="lw-tiles xh-tiles">{tiles.map((o) => <L.ObjTile key={o.id} o={o} onOpen={() => (onProject ? onProject(o.id) : go(projUrl(o.id)))} />)}</div>
        </React.Fragment> : null}
        {extra || null}
        <Away me={me} />
      </div>);
  }
  window.ExecHome = ExecHome;
})();
