/* accountant-v2-app.jsx — кабинет бухгалтера в виде кабинета клиента (KSH-457): шапка, главная со сводкой, разделы — окнами по #hash.
   Собран из библиотеки виджетов lk-widgets.jsx (window.LKW) на данных accountant-views.js (window.AccountantViews).
   Главная: сводка денег, «Сейчас важно», оплаты на сверке, дебиторка по срокам, к оплате подрядчикам, проекты, чаты, «Мои задачи».
   Окна: #check — все оплаты на сверке; #pay=<src>:<id>:<payId> — сверка одной оплаты: «Подтвердить» или «Отклонить» с причиной (клиент её видит);
   #debts — единая дебиторка (та же формула, что у менеджера и руководителя: ProjectStore.views.arAging); #payables — подрядчикам к оплате
   и заказы поставщикам в пути; #projects; #proj=<id> — финансы проекта: график оплат, «Выставить счёт», «Внести поступление» (сумма, дата,
   способ, документ), сверка, документы проекта; #chat[=<pid>:<tid>].
   Действия — ProjectStore.registerPayment / rejectPayment / issueInvoice / verifyPayment / paySub, DealContracts.verifyPayment.
   Документы и Отчёты прежнего кабинета — в «Ещё». */
(function () {
  'use strict';
  const P = window.ProjectStore, AV = window.AccountantViews, W = window.LKW, A = window.AccessStore;
  const { Ic, Header, Modal, FactsBand, NowCards, RowsW, ChatsW, rub, plural, cap, dateR, short } = W;
  const t0 = () => new Date().toISOString().slice(0, 10);
  const dm = (d) => (d ? String(d).slice(8, 10) + '.' + String(d).slice(5, 7) + '.' + String(d).slice(2, 4) : '');

  function useMe() {
    const acc = A && A.currentAccount ? A.currentAccount() : null;
    const ac = W.access(acc, ['accountant', 'super']);
    return { id: acc ? acc.profileId : null, name: (acc && acc.name) || 'Бухгалтер', role: acc && acc.role === 'super' ? 'super' : 'accountant',
      ...(() => { // главная (dash), «Проекты», «Долги» и «Чаты» — отдельные разделы: выключенная главная не закрывает выданные
        const home = ac.zone('dash'), projects = ac.zone('projects'), debts = ac.zone('ledger'), chat = ac.zone('chat');
        return { deny: ac.deny || (home || projects || debts || chat ? '' : 'Кабинет бухгалтера не входит в выданный доступ.'), home, projects, debts, chat };
      })() };
  }
  const EVS = ['storage', 'obitel:sync', 'obitel:deal-docs', 'obitel:deal-chat', 'remontpro:forms-updated'];
  function useStore() {
    const [, tick] = React.useState(0);
    React.useEffect(() => (P ? P.subscribe(() => tick((x) => x + 1)) : undefined), []);
    React.useEffect(() => { const on = () => tick((x) => x + 1); EVS.forEach((e) => window.addEventListener(e, on)); return () => EVS.forEach((e) => window.removeEventListener(e, on)); }, []);
  }
  function useHash() {
    const read = () => decodeURIComponent((window.location.hash || '').replace('#', ''));
    const [m, setM] = React.useState(read());
    React.useEffect(() => { const on = () => setM(read()); window.addEventListener('hashchange', on); return () => window.removeEventListener('hashchange', on); }, []);
    const open = (id) => { window.location.hash = id; };
    const close = () => { history.replaceState(null, '', window.location.pathname + window.location.search); setM(''); };
    return [m, open, close];
  }
  const greeting = () => { const h = new Date().getHours(); return h < 5 ? 'Доброй ночи' : h < 12 ? 'Доброе утро' : h < 18 ? 'Добрый день' : 'Добрый вечер'; };
  const todayLine = () => cap(new Date().toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' }));
  const when = (iso) => { if (!iso) return ''; const d = String(iso).slice(0, 10); return d === t0() ? new Date(iso).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }) : dateR(d, { month: 'short' }); };
  const go = (url) => { window.location.href = url; };
  const keep = (page) => { const s = window.location.search; return page + (s || ''); };

  const NAV = [['', 'Главная'], ['check', 'Сверка'], ['debts', 'Долги'], ['projects', 'Проекты'], ['chat', 'Чаты']];
  const PHONE = ['', 'check', 'debts', 'projects'];
  const MORE = [['payables', 'К оплате подрядчикам'], ['tools.html?role=accountant', 'Инструменты'], ['accountant-documents.html', 'Документы'], ['accountant-reports.html', 'Отчёты'], ['accountant-profile.html', 'Профиль']];
  const PST = { paid: 'pill-g', check: 'pill-n', overdue: 'pill-n cv-over', expected: 'pill-n', planned: 'pill-g' };

  const nowRows = (queue, open) => queue.slice(0, 3).map((q) => ({ key: q.key, kindL: q.kindL, late: q.sev === 'red', title: q.title, sub: q.sub, right: q.sev === 'red' ? 'срочно' : '', act: { text: q.act, onClick: () => open(q.open) } }));

  /* «Мои задачи»: очередь бухгалтера + задачи сделок на бухгалтере (TaskViews.inbox) */
  function myInbox(queue, open) {
    const T = window.TaskViews; if (!T) return [];
    // срок строки: долг и счёт к выставлению — по сроку платежа (в «Просрочено» группой «Срок был …»), сверка и подрядчики — сегодня
    const q = queue.map((x) => ({ id: 'aq:' + x.key, kind: x.kind, kindL: x.kindL, title: x.title, sub: x.sub, due: x.due || undefined, now: !x.due || undefined,
      status: 'open', statusL: x.kindL, next: { who: 'me', l: x.act }, act: () => open(x.open) }));
    const deal = T.inbox ? T.inbox('accountant', 'accountant', t0()).map((r) => Object.assign({}, r, { act: () => { if (r.kind === 'returned' && r.dealId && r.key && T.markTaskSeen) T.markTaskSeen(r.dealId, r.key, { role: 'accountant', name: 'Бухгалтер' }); if (r.href) go(r.href); } })) : [];
    const order = (r) => (r.late ? 0 : r.now ? 1 : 2);
    return q.concat(deal).sort((a, b) => order(a) - order(b) || String(a.due || '9999').localeCompare(String(b.due || '9999')));
  }

  /* ───── главная ───── */
  function Home({ me, data, open }) {
    const { check, ar, pay, projs, queue, chats } = data;
    const red = queue.filter((q) => q.sev === 'red').length;
    const toInv = projs.reduce((a, p) => a + p.toInvoice.length, 0);
    const first = (me.name || '').split(' ')[0];
    const T = window.TaskViews;
    return (
      <div className="cv-page lw-page">
        <Header nav={NAV} more={MORE} phone={PHONE} cur="" right={<span className="cv-ava" title={me.name}>{me.name.split(' ').map((w) => w[0]).join('').slice(0, 2)}</span>} />
        <main id="main" tabIndex={-1} className="cv-main">
          <section className="cv-hero">
            <div><div className="lab">{todayLine()} · {projs.length} {plural(projs.length, 'проект', 'проекта', 'проектов')} с деньгами в работе</div><h1 className="cv-hello">{greeting()}{first ? ', ' + first : ''}</h1></div>
            <div className="cv-hero-act">
              {check.length ? <button type="button" className="btn-k" onClick={() => open('check')}>Сверить · {check.length}</button>
                : <span className="pill-g"><span className="dot" />Всё сверено</span>}
            </div>
          </section>

          <FactsBand label="Сводка денег"
            live={<span className="now">{red ? <React.Fragment><i className="cv-pulse" aria-hidden="true" /><span>Срочно: {red} {plural(red, 'дело', 'дела', 'дел')}</span></React.Fragment> : 'Срочного нет'}</span>}
            facts={[
              { v: check.length + ' ' + plural(check.length, 'оплата', 'оплаты', 'оплат'), lab: check.length ? 'Ждут сверки · ' + rub(check.reduce((a, x) => a + x.amount, 0)) : 'На сверке ничего нет', onClick: () => open('check') },
              { v: rub(ar.overdue), lab: 'Просрочено клиентами', late: ar.overdue > 0, onClick: () => open('debts') },
              { v: rub(ar.total - ar.overdue), lab: 'Ожидаем до срока', onClick: () => open('debts') },
              { v: rub(pay.subSum), lab: pay.subs.length ? 'К оплате подрядчикам · ' + pay.subs.length : 'Подрядчикам платить нечего', onClick: () => open('payables') },
              { v: toInv + ' ' + plural(toInv, 'счёт', 'счёта', 'счетов'), lab: toInv ? 'Пора выставить по графику' : 'Счета выставлены вовремя', onClick: () => open('projects') },
            ]} />

          <NowCards rows={nowRows(queue, open)} />

          <section className="cv-two lw-two">
            <RowsW id="ac-check-h" title="Оплаты на сверке" n={check.length}
              rows={check.slice(0, 8).map((r) => ({ key: r.key, ic: 'wallet', late: !r.proof, title: r.client + ' · ' + rub(r.amount), sub: r.title + ' · ' + short(r.obj) + (r.proof ? '' : ' · нет чека'), right: r.paidAt ? 'оплачено ' + dm(r.paidAt) : '', onClick: () => open('pay=' + r.key) }))}
              empty="Клиенты ничего не отметили оплаченным — сверять нечего." onOpen={() => open('check')} text={'Все оплаты' + (check.length > 8 ? ' · ' + check.length : '')} />
            <div className="cv-side">
              <section className="cv-w cv-apr-w lw-rows" aria-labelledby="ac-ar-h">
                <W.WHead id="ac-ar-h" title="Дебиторка" sub={rub(ar.total)} text="Все долги" onOpen={() => open('debts')} />
                <div className="ac-buckets">{ar.buckets.map((b) => (
                  <button type="button" key={b.key} className={'ac-bucket' + (b.key !== 'cur' && b.amount ? ' is-over' : '')} onClick={() => open('debts')}>
                    <span className="lab">{b.label}</span><b>{rub(b.amount)}</b><span className="lab">{b.count} {plural(b.count, 'счёт', 'счёта', 'счетов')}</span></button>))}</div>
              </section>
              <ChatsW chats={chats.map((c) => Object.assign({}, c, { when: when(c.at) }))} onOpen={() => open('chat')} onPick={(c) => open('chat=' + c.pid + ':' + c.id)} empty="Чатов с бухгалтерией пока нет." />
            </div>
          </section>

          <section className="cv-two lw-two">
            <RowsW id="ac-proj-h" title="Проекты" n={projs.filter((p) => p.overdueN).length} className="is-grow"
              rows={projs.slice(0, 8).map((p) => ({ key: p.id, ic: 'doc', late: p.overdue > 0, title: p.title, sub: [p.client, 'оплачено ' + rub(p.paid) + ' из ' + rub(p.contract)].join(' · '),
                right: p.overdue ? rub(p.overdue) : p.check ? rub(p.check) : p.toInvoice.length ? p.toInvoice.length + ' к выставлению' : '', rightLab: p.overdue ? 'просрочено' : p.check ? 'на сверке' : '', onClick: () => open('proj=' + p.id) }))}
              empty="Проектов с деньгами в работе нет." onOpen={() => open('projects')} text="Все проекты" />
            <RowsW id="ac-sub-h" title="К оплате подрядчикам" n={pay.subs.length}
              rows={pay.subs.slice(0, 6).map((r) => ({ key: r.pid + r.orderId + r.part, ic: 'tool', title: r.subName + ' · ' + rub(r.amount), sub: r.partLabel + ' · ' + short(r.obj), onClick: () => open('payables') }))}
              empty="Аванс появляется после заказа, остаток — после приёмки работ." onOpen={() => open('payables')} text="Все платежи" />
          </section>

          {T && <section id="ac-tasks" className="cv-w lw-gw lw-scope" aria-label="Мои задачи">
            <W.TaskList title="Мои задачи" t0={t0()} onOpen={(r) => (r.act ? r.act() : r.href ? go(r.href) : null)}
              tabs={[{ id: 'in', label: 'Мне сделать', rows: myInbox(queue, open), empty: 'Всё сверено, счета выставлены.', boardRows: myInbox(queue, open).concat(T.inboxDone ? T.inboxDone('accountant', t0()) : []), columns: T.IN_COLUMNS, colOf: T.inCol }]
                .concat(T.outbox ? [{ id: 'out', label: 'Отправлено мной', rows: T.outbox({ role: 'accountant' }, t0()), empty: 'Вы ничего не возвращали на доработку.', buckets: T.OUT_BUCKETS, bucketOf: T.outBucket, boardRows: T.outbox({ role: 'accountant' }, t0(), { closed: true }), columns: T.OUT_COLUMNS, colOf: T.outCol }] : [])} />
          </section>}
        </main>
      </div>);
  }

  /* ───── сверка оплат ───── */
  function CheckModal({ data, open, close }) {
    return (
      <Modal size="wide" title="Оплаты на сверке" sub={data.check.length ? data.check.length + ' · ' + rub(data.check.reduce((a, x) => a + x.amount, 0)) : 'всё сверено'} onClose={close}>
        {data.check.length ? <div className="rows mg-rows">{data.check.map((r) => (
          <button type="button" key={r.key} className={'r lw-r mg-row' + (r.proof ? '' : ' is-over')} onClick={() => open('pay=' + r.key)}>
            <span className="tx"><span className="t">{r.client} · {rub(r.amount)}</span><span className="lab">{r.title} · {short(r.obj)}{r.proof ? '' : ' · нет чека'}</span></span>
            <span className="by"><b>{r.paidAt ? 'оплачено ' + dm(r.paidAt) : ''}</b></span>
          </button>))}</div> : <div className="note-s" style={{ marginTop: 18 }}><Ic n="check" c="#2F5D3A" s={16} /><span>Клиенты ничего не отметили оплаченным — сверять нечего.</span></div>}
        <div className="lab" style={{ marginTop: 16 }}>Подтвердите, когда деньги пришли на счёт. Если денег нет — отклоните с причиной: клиент увидит её, счёт снова станет к оплате.</div>
      </Modal>);
  }
  function PayModal({ k, data, me, close, open }) {
    const r = data.check.find((x) => x.key === k);
    const [rej, setRej] = React.useState(false);
    const [why, setWhy] = React.useState('');
    const [err, setErr] = React.useState('');
    const [done, setDone] = React.useState('');
    const actor = { role: 'accountant', name: me.name };
    if (done) return (
      <Modal title={done === 'ok' ? 'Оплата подтверждена' : 'Оплата отклонена'} onClose={close}>
        <div className="note-s" style={{ marginTop: 16 }}><Ic n="check" c="#2F5D3A" s={16} /><span>{done === 'ok' ? 'Платёж закрыт. Если он держал этап, этап открылся.' : 'Счёт снова к оплате, клиент видит причину.'}</span></div>
        <div className="cv-dbtn" style={{ display: 'flex', marginTop: 16 }}><button type="button" className="btn-l" onClick={() => open('check')}>К сверке</button></div>
      </Modal>);
    if (!r) return <Modal title="Оплата уже сверена" onClose={close}><div className="lab" style={{ marginTop: 16 }}>Эта оплата больше не ждёт сверки.</div></Modal>;
    const run = (fn, d) => { try { fn(); setErr(''); setDone(d); } catch (e) { setErr(e.message); } };
    return (
      <Modal title={r.title} sub={[r.client, r.obj].join(' · ')} onClose={close}
        head={r.pid ? <button type="button" className="lw-btn-l" onClick={() => open('proj=' + r.pid)}>Финансы проекта</button> : null}>
        {err && <div className="att" role="alert" style={{ marginTop: 12 }}><Ic n="alert" s={16} /><span>{err}</span></div>}
        <div className="card cv-dec" style={{ marginTop: 16 }}>
          <dl className="cv-meta"><div><dt>Сумма</dt><dd className="hot">{rub(r.amount)}</dd></div><div><dt>Клиент отметил</dt><dd>{r.paidAt ? dm(r.paidAt) : '—'}</dd></div>
            <div><dt>Чек</dt><dd>{r.proof ? (r.src === 'deal' ? 'приложен' : 'клиент отметил оплату в кабинете') : 'не приложен'}</dd></div></dl>
          {rej && <textarea className="cv-ta" rows={2} autoFocus value={why} onChange={(e) => setWhy(e.target.value)} placeholder="Что не так: денег нет на счёте, другая сумма… — клиент увидит" aria-label="Причина" style={{ marginTop: 12 }} />}
          <div className="cv-dbtn" style={{ display: 'flex', gap: 8, marginTop: 14 }}>
            {rej ? <React.Fragment><button type="button" className="btn-l" onClick={() => setRej(false)}>Отмена</button><button type="button" className="btn-k" disabled={!why.trim()} onClick={() => run(() => P.rejectPayment(r.pid, r.id, why, actor), 'rej')}>Отправить отказ</button></React.Fragment>
              : <React.Fragment>{r.canReject && <button type="button" className="btn-l" onClick={() => setRej(true)}>Денег нет</button>}<button type="button" className="btn-k" disabled={!r.proof} onClick={() => run(() => AV.verify(r, actor), 'ok')}>Деньги пришли</button></React.Fragment>}
          </div>
          {!r.proof && <div className="lab" style={{ marginTop: 10 }}>Без чека подтвердить нельзя — попросите менеджера сделки приложить его.</div>}
        </div>
      </Modal>);
  }

  /* ───── дебиторка ───── */
  function DebtsModal({ data, open, close }) {
    const { ar } = data;
    const [b, setB] = React.useState('all');
    const rows = ar.rows.filter((x) => b === 'all' || x.bucket === b);
    return (
      <Modal size="wide" title="Дебиторка" sub={'Всего ' + rub(ar.total) + (ar.overdue ? ' · просрочено ' + rub(ar.overdue) : '')} onClose={close}>
        <div className="mg-tabs"><W.CalTabs kinds={[['all', 'Все']].concat(ar.buckets.map((x) => [x.key, x.label]))} tab={b} setTab={setB}
          counts={ar.buckets.reduce((a, x) => Object.assign(a, { [x.key]: x.count }), { all: ar.rows.length })} label="Срок долга" /></div>
        <div className="ac-buckets is-wide">{ar.buckets.map((x) => <div key={x.key} className={'ac-bucket' + (x.key !== 'cur' && x.amount ? ' is-over' : '')}><span className="lab">{x.label}</span><b>{rub(x.amount)}</b></div>)}</div>
        {rows.length ? <div className="rows mg-rows">{rows.map((x) => (
          <button type="button" key={x.id} className={'r lw-r mg-row' + (x.overdue ? ' is-over' : '')} onClick={() => open(x.pid ? 'proj=' + x.pid : 'debts')}>
            <span className="tx"><span className="t">{x.client} · {rub(x.amount)}</span><span className="lab">{x.title} · {short(x.obj)}{x.rejected ? ' · оплата не найдена ' + dm(x.rejected.at) : ''}</span></span>
            <span className="by"><b>{x.overdue ? 'просрочка ' + x.days + ' дн' : x.due ? 'до ' + dm(x.due) : 'без срока'}</b></span>
          </button>))}</div> : <div className="lab" style={{ marginTop: 16 }}>В этой корзине счетов нет.</div>}
        <div className="lab" style={{ marginTop: 16 }}>Долг — выставленный и не оплаченный счёт. Те же цифры видят менеджер и руководитель.</div>
      </Modal>);
  }

  /* ───── подрядчики и поставщики ───── */
  function PayablesModal({ data, me, close }) {
    const [err, setErr] = React.useState('');
    const { pay } = data;
    const paySub = (r) => { try { P.paySub(r.pid, r.orderId, r.part, { role: 'accountant', name: me.name }); setErr(''); } catch (e) { setErr(e.message); } };
    return (
      <Modal size="wide" title="К оплате" sub={'Подрядчикам ' + rub(pay.subSum) + (pay.orders.length ? ' · поставщикам в пути ' + rub(pay.orderSum) : '')} onClose={close}>
        {err && <div className="att" role="alert" style={{ marginTop: 12 }}><Ic n="alert" s={16} /><span>{err}</span></div>}
        <section style={{ marginTop: 20 }}><h2 className="h2" style={{ fontSize: 20 }}>Подрядчикам</h2>
          {pay.subs.length ? <div className="rows mg-rows">{pay.subs.map((r) => (
            <div key={r.pid + r.orderId + r.part} className="r lw-r">
              <span className="tx"><span className="t">{r.subName} · {rub(r.amount)}</span><span className="lab">{r.partLabel} · {short(r.obj)} · {r.basis}</span></span>
              <span className="lw-racts"><button type="button" className="lw-btn-k" onClick={() => paySub(r)}>Оплачено</button></span>
            </div>))}</div> : <div className="lab" style={{ marginTop: 8 }}>Аванс появляется после размещения заказа, остаток — после приёмки работ.</div>}
        </section>
        <section style={{ marginTop: 24 }}><h2 className="h2" style={{ fontSize: 20 }}>Поставщикам · заказы в пути</h2>
          {pay.orders.length ? <div className="rows mg-rows">{pay.orders.map((o) => (
            <div key={o.id} className="r lw-r"><span className="tx"><span className="t">{o.supplier} · {rub(o.amount)}</span><span className="lab">{o.id} · {short(o.obj)}{o.eta ? ' · привезут ' + o.eta : ''}</span></span></div>))}</div>
            : <div className="lab" style={{ marginTop: 8 }}>Заказов в пути нет.</div>}
          <div className="lab" style={{ marginTop: 10 }}>Оплату поставщикам пока ведут закупки — здесь для сведения.</div>
        </section>
      </Modal>);
  }

  /* ───── проекты ───── */
  function ProjectsModal({ data, open, close }) {
    return (
      <Modal size="wide" title="Проекты" sub={data.projs.length + ' с деньгами в работе'} onClose={close}>
        {data.projs.length ? <div className="mg-list">{data.projs.map((p) => (
          <button type="button" key={p.id} className="mg-deal" onClick={() => open('proj=' + p.id)}>
            <span className="t">{p.title}<span className="lab"> · {p.client}</span></span>
            <span className="lab">оплачено {rub(p.paid)} из {rub(p.contract)}{p.check ? ' · на сверке ' + rub(p.check) : ''}{p.toInvoice.length ? ' · ' + p.toInvoice.length + ' к выставлению' : ''}</span>
            <span className="r">{p.overdue ? <b className="mg-late">{rub(p.overdue)}</b> : <b>{rub(p.expected)}</b>}<span className="lab">{p.overdue ? 'просрочено' : 'ожидаем'}</span></span>
          </button>))}</div> : <div className="lab" style={{ marginTop: 20 }}>Проектов с деньгами в работе нет.</div>}
      </Modal>);
  }
  const METHODS = [['transfer', 'Перевод'], ['card', 'Карта'], ['cash', 'Наличные'], ['other', 'Другое']];
  function ProjectModal({ id, data, me, open, close }) {
    const raw = P.get(id);
    const p = raw ? AV.project(raw, t0()) : null;
    const [form, setForm] = React.useState(null);
    const [err, setErr] = React.useState('');
    const [ok, setOk] = React.useState('');
    if (!p) return <Modal title="Проект не найден" onClose={close}><div className="lab" style={{ marginTop: 16 }}>Такого проекта нет.</div></Modal>;
    const actor = { role: 'accountant', name: me.name };
    const run = (fn, msg) => { try { fn(); setErr(''); setOk(msg); setForm(null); } catch (e) { setErr(e.message); } };
    const startReg = (x) => { setOk(''); setErr(''); setForm({ payId: x.id, amount: String(x.amount), date: t0(), method: 'transfer', file: null }); };
    const set = (k, v) => setForm(Object.assign({}, form, { [k]: v }));
    // документ к поступлению — через общую загрузку файлов (Files.upload: облако или ссылка вкладки), иначе только имя
    const pickFile = (e) => { const f = e.target.files && e.target.files[0]; if (!f) return; const F = window.Files; set('file', { name: f.name, url: '' });
      if (F && F.upload) F.upload(f, { pid: id, kind: 'payment' }).then((r) => setForm((cur) => (cur ? Object.assign({}, cur, { file: { name: r.name || f.name, url: r.url || '' } }) : cur))).catch(() => {}); };
    return (
      <Modal size="wide" title={p.title} sub={[p.client, p.id].filter(Boolean).join(' · ')} onClose={close}
        head={<button type="button" className="lw-btn-l" onClick={() => open('chat=' + p.id + ':')}>Чат проекта</button>}>
        {err && <div className="att" role="alert" style={{ marginTop: 12 }}><Ic n="alert" s={16} /><span>{err}</span></div>}
        {ok && <div className="note-s" role="status" style={{ marginTop: 12 }}><Ic n="check" c="#2F5D3A" s={16} /><span>{ok}</span></div>}
        <FactsBand label="Деньги проекта" facts={[
          { v: rub(p.contract), lab: 'Договор' },
          { v: rub(p.paid), lab: 'Оплачено и сверено' },
          { v: p.overdue ? rub(p.overdue) : rub(p.expected), lab: p.overdue ? 'Просрочено · ' + p.overdueN + ' ' + plural(p.overdueN, 'счёт', 'счёта', 'счетов') : 'Ожидаем до срока', late: p.overdue > 0 },
          { v: rub(p.check), lab: p.checkN ? 'На сверке' : 'На сверке ничего нет' },
          { v: rub(p.planned), lab: 'Впереди по графику' + (p.toInvoice.length ? ' · ' + p.toInvoice.length + ' пора выставить' : '') },
        ]} />
        <div className="cv-two lw-two">
          <section className="cv-w cv-apr-w lw-rows is-grow" aria-labelledby="ac-pays-h">
            <W.WHead id="ac-pays-h" title="График оплат" n={p.overdueN} />
            <div className="rows">{p.pays.map((x) => (
              <div key={x.id} className={'r lw-r' + (x.state === 'overdue' ? ' is-over' : '')}>
                <span className="tx"><span className="t">{x.title}</span>
                  <span className="lab">{rub(x.amount)}{x.due ? ' · срок ' + dm(x.due) : ''}{x.state === 'overdue' ? ' · просрочка ' + x.days + ' дн' : ''}{x.receipt ? ' · поступило ' + dm(x.receipt.date) + (x.receipt.file ? ' · ' + x.receipt.file.name : '') : x.state === 'paid' && x.paidAt ? ' · оплачено ' + dm(x.paidAt) : ''}{x.rejected && x.state !== 'paid' ? ' · отклонено: ' + x.rejected.comment : ''}</span>
                  {form && form.payId === x.id && <span className="ac-form" onClick={(e) => e.stopPropagation()}>
                    <label><span className="lab">Сумма, ₽</span><input value={form.amount} onChange={(e) => set('amount', e.target.value)} inputMode="numeric" aria-label="Сумма" /></label>
                    <label><span className="lab">Дата поступления</span><input type="date" value={form.date} max={t0()} onChange={(e) => set('date', e.target.value)} aria-label="Дата" /></label>
                    <span className="ac-methods" role="radiogroup" aria-label="Способ">{METHODS.map(([k, l]) => <button type="button" key={k} role="radio" aria-checked={form.method === k} className={'pill-n' + (form.method === k ? ' on' : '')} onClick={() => set('method', k)}>{l}</button>)}</span>
                    <span className="ac-file"><label className="lw-btn-l">{form.file ? 'Заменить файл' : 'Приложить платёжку'}<input type="file" accept="image/*,.pdf" onChange={pickFile} aria-label="Платёжка или выписка" /></label><span className="lab">{form.file ? form.file.name : 'необязательно'}</span></span>
                    <span className="cv-dbtn" style={{ display: 'flex', gap: 8 }}><button type="button" className="btn-l" onClick={() => setForm(null)}>Отмена</button>
                      <button type="button" className="btn-k" onClick={() => run(() => P.registerPayment(p.id, x.id, form, actor), 'Поступление внесено: ' + x.title)}>Внести</button></span>
                  </span>}
                </span>
                <span className={PST[x.state]}>{x.state === 'planned' && x.invoiceDue ? 'Пора выставить' : x.stateL}</span>
                {!(form && form.payId === x.id) && <span className="lw-racts">
                  {x.state === 'planned' && <button type="button" className="lw-btn-l" onClick={() => run(() => P.issueInvoice(p.id, x.id, actor), 'Счёт выставлен: ' + x.title)}>Выставить счёт</button>}
                  {(x.state === 'expected' || x.state === 'overdue') && <button type="button" className="lw-btn-k" onClick={() => startReg(x)}>Внести поступление</button>}
                  {x.state === 'check' && <button type="button" className="lw-btn-k" onClick={() => open('pay=project:' + p.id + ':' + x.id)}>Сверить</button>}
                </span>}
              </div>))}</div>
            {!p.pays.length && <div className="lab" style={{ marginTop: 10 }}>Графика оплат нет.</div>}
          </section>
          <section className="cv-w cv-apr-w lw-rows" aria-labelledby="ac-docs-h">
            <W.WHead id="ac-docs-h" title="Документы проекта" n={p.docs.filter((d) => d.status === 'pending').length} />
            {p.docs.length ? <div className="rows">{p.docs.map((d) => (
              <div key={d.id} className="r lw-r"><span className="tx"><span className="t">{d.title}</span><span className="lab">{d.amount ? rub(d.amount) + ' · ' : ''}{dm(d.at)}</span></span>
                <span className={d.status === 'pending' ? 'pill-n' : 'pill-g'}>{d.status === 'pending' ? (d.kind === 'act' ? 'у клиента' : 'ждёт') : d.status === 'rejected' ? 'отклонён' : 'подписан'}</span></div>))}</div>
              : <div className="lab" style={{ marginTop: 10 }}>Документов пока нет.</div>}
          </section>
        </div>
      </Modal>);
  }

  /* ───── чаты проектов, где есть бухгалтерия ───── */
  const WHO = { client: 'Клиент', manager: 'Менеджер', foreman: 'Прораб', procurement: 'Закупки', accountant: 'Вы', executor: 'Мастер', super: 'Руководитель', designer: 'Дизайнер' };
  function ChatModal({ data, sel, open, close }) {
    const [pid0, tid0] = (sel || '').split(':');
    const cur = data.chats.find((c) => c.pid === pid0 && (!tid0 || c.id === tid0)) || data.chats[0] || null;
    const [txt, setTxt] = React.useState('');
    const thread = cur ? ((P.get(cur.pid) || {}).chat || { threads: [] }).threads.find((t) => t.id === cur.id) : null;
    const send = () => { if (!txt.trim() || !thread) return; P.chatSend(cur.pid, thread.id, { from: 'accountant', t: txt.trim() }); setTxt(''); };
    return (
      <Modal size="wide" title="Чаты" sub="проекты, где есть бухгалтерия" onClose={close}>
        <div className="lw-chat">
          <div className="lw-chl">{data.chats.map((c) => (
            <button type="button" key={c.pid + c.id} className={'lw-chr' + (cur && c.pid === cur.pid && c.id === cur.id ? ' on' : '') + (c.isNew ? ' is-new' : '')} onClick={() => open('chat=' + c.pid + ':' + c.id)}>
              <span className="t">{short(c.obj)}<span className="lab"> · {c.title}</span></span><span className="lab">{c.who ? (WHO[c.who] || c.who) + ': ' : ''}{c.text}</span><span className="tm lab">{when(c.at)}</span></button>))}</div>
          <div className="lw-chv">{thread ? <React.Fragment>
            <div className="lw-chh"><b>{cur.obj}</b><span className="lab">{thread.members.filter((m) => m !== 'accountant').map((m) => WHO[m] || m).join(', ')}</span>
              <button type="button" className="cv-arrow-btn" onClick={() => open('proj=' + cur.pid)}>Финансы проекта<Ic n="ne" s={14} /></button></div>
            <div className="lw-msgs cv-scroll">{thread.msgs.map((m) => (
              <div key={m.id} className={'lw-msg' + (m.from === 'accountant' ? ' mine' : '')}><span className="lab">{WHO[m.from] || m.from} · {when(m.at)}</span>
                {m.t ? <span className="b">{m.t}</span> : null}{m.media && m.media.url ? <img src={m.media.url} alt={m.media.name || ''} /> : null}</div>))}</div>
            <div className="lw-send"><input value={txt} onChange={(e) => setTxt(e.target.value)} placeholder="Написать" aria-label="Сообщение" onKeyDown={(e) => { if (e.key === 'Enter') send(); }} /><button type="button" className="lw-btn-k" disabled={!txt.trim()} onClick={send}>Отправить</button></div>
          </React.Fragment> : <div className="empty">Чатов с бухгалтерией пока нет. Менеджер или прораб добавляет бухгалтерию в чат проекта.</div>}</div>
        </div>
      </Modal>);
  }

  /* ───── данные и маршрутизация окон ───── */
  function collect() {
    const t = t0();
    return { check: AV.toCheck(), ar: AV.receivables(t), pay: AV.payables(), projs: AV.projects(t), queue: AV.queue(t), chats: AV.chats() };
  }

  function App() {
    useStore();
    const me = useMe();
    const [modal, open, close] = useHash();
    if (!P || !AV) return <div className="cv-page"><div className="empty">Кабинет не загрузился. Обновите страницу.</div></div>;
    const data = collect();
    if (me.deny) return <W.Denied why={me.deny} />;
    const arg = (k) => (modal.indexOf(k + '=') === 0 ? modal.slice(k.length + 1) : null);
    const projWin = modal === 'projects' || !!arg('proj');
    const chatWin = modal === 'chat' || arg('chat') != null;
    return (
      <React.Fragment>
        {me.home ? <Home me={me} data={data} open={open} /> : <W.Denied title="Главная закрыта" why="Главная кабинета не входит в выданный доступ — открытые вам разделы работают по своим ссылкам." />}
        {modal === 'check' && me.home && <CheckModal data={data} open={open} close={close} />}
        {arg('pay') && me.home && <PayModal key={arg('pay')} k={arg('pay')} data={data} me={me} open={open} close={close} />}
        {projWin && !me.projects && <W.Closed what="Раздел «Проекты»" onClose={close} />}
        {modal === 'debts' && !me.debts && <W.Closed what="Раздел «Долги»" onClose={close} />}
        {chatWin && !me.chat && <W.Closed what="Раздел «Чаты»" onClose={close} />}
        {modal === 'debts' && me.debts && <DebtsModal data={data} open={open} close={close} />}
        {modal === 'payables' && me.home && <PayablesModal data={data} me={me} close={close} />}
        {modal === 'projects' && me.projects && <ProjectsModal data={data} open={open} close={close} />}
        {arg('proj') && me.projects && <ProjectModal key={arg('proj')} id={arg('proj')} data={data} me={me} open={open} close={close} />}
        {chatWin && me.chat && <ChatModal data={data} sel={arg('chat')} open={open} close={close} />}
      </React.Fragment>);
  }

  window.AccountantV2 = { App, collect, myInbox };
  if (!window.__ACCOUNTANT_V2_NO_MOUNT) ReactDOM.createRoot(document.getElementById('root')).render(<App />);
})();
