/* lk-docs.jsx — «Документы и акты» для кабинетов сотрудников (прораб первым), в стиле окон кабинета клиента.
   DocsW — окно по объектам: слева этапы, где все работы приняты, а этап не закрыт («Закрыть этап»: закрытие последнего этапа фазы
   отправляет клиенту акт фазы и выставляет её счёт — без этого следующая фаза не откроется), и акты у клиента: ждут подписи или
   клиент вернул их с комментарием. Справа — акты и оплаты по фазам каждого объекта, договор и допсоглашения. Ниже — пакет сдачи:
   исполнительные схемы и паспорта, которые прораб загружает по ходу работ; клиент получит их в «Приёмке объекта».
   Действия — функции ProjectStore через кабинет: onCloseStage (closeStage), onUpload (addHandoverDoc), onRemove (removeHandoverDoc).
   Данные — ForemanViews.docs(). Exports on window: LKW.DocsW (дописывает в библиотеку lk-widgets.jsx, грузится после неё). */
(function () {
  'use strict';
  const W = window.LKW;
  const { Ic, Modal, CalTabs, rub, plural, dateR, short } = W;
  const dm = (d) => (d ? dateR(d, { month: 'short' }) : '');
  const stages = (n) => n + ' ' + plural(n, 'этап', 'этапа', 'этапов');
  const quote = (list) => list.map((x) => '«' + x + '»').join(', ');

  /* этап к закрытию: сколько работ принято и что будет после закрытия — акт клиенту или «в фазе ещё N этапов» */
  function CloseCard({ r, one, onClose, onObject }) {
    const [err, setErr] = React.useState('');
    const go = () => { const res = onClose(r) || {}; if (res.error) setErr(res.error); };
    return (
      <div className="cv-w cv-dlcard lw-dl is-ask">
        <div className="hd">
          <div style={{ minWidth: 0 }}>
            <div className="t">{r.name}</div>
            <div className="lab" style={{ marginTop: 3 }}>{one ? '' : short(r.obj) + ' · '}фаза «{r.phase}»</div>
          </div>
          <span className="pill-g">всё принято</span>
        </div>
        <dl className="cv-meta">
          <div><dt>Работы</dt><dd>{r.works} из {r.works} приняты{r.since ? ', последняя ' + dm(r.since) : ''}</dd></div>
          <div><dt>После закрытия</dt><dd>{r.last ? 'акт фазы на ' + rub(r.amount) + ' уйдёт клиенту на подпись, выставится счёт фазы'
            : 'в фазе ещё ' + stages(r.left.length) + ': ' + r.left.join(', ') + '. Акт уйдёт клиенту, когда закроете последний'}</dd></div>
        </dl>
        {err && <div className="att" style={{ marginTop: 12 }}><Ic n="alert" s={16} /><span>{err}</span></div>}
        <div className="lw-dlact">
          {onObject && !one ? <button type="button" className="cv-arrow-btn" onClick={() => onObject(r.pid)}>Объект<Ic n="ne" s={14} /></button> : <span />}
          <button type="button" className="lw-btn-k" onClick={go}><Ic n="check" s={15} />Закрыть этап</button>
        </div>
      </div>);
  }
  // этапы, закрытые сейчас в этом окне: что произошло после каждого — одной карточкой, пока окно открыто
  function ClosedCard({ list }) {
    return (
      <div className="cv-w cv-dlcard lw-dok">
        {list.map((r) => (
          <div key={r.pid + r.stageId} className="lw-dokr">
            <span className="ic"><Ic n="check" s={14} /></span>
            <span className="tx"><span className="t">Этап «{r.name}» закрыт</span>
              <span className="lab">{r.last ? 'Акт фазы «' + r.phase + '» на ' + rub(r.amount) + ' ушёл клиенту на подпись, счёт фазы выставлен.' : 'В фазе ещё ' + stages(r.left.length) + '. Акт уйдёт клиенту, когда закроете последний.'}</span></span>
          </div>))}
      </div>);
  }

  /* фаза строкой: акт (подписан, у клиента, вернули), оплата фазы; идущая фаза — сколько принято, будущая — тише */
  // open — этапы фазы, где всё принято, но их не закрыли: пока они открыты, акта нет
  function PhaseRow({ ph, open }) {
    const a = ph.act;
    const lab = a ? (a.state === 'signed' ? 'акт подписан ' + dm(a.signedAt) : a.state === 'rejected' ? 'клиент вернул акт' + (a.comment ? ': ' + a.comment : '') : 'акт отправлен ' + dm(a.at) + ', ждёт подписи клиента')
      : ph.state === 'done' && open.length ? 'все работы приняты · закройте ' + (open.length > 1 ? 'этапы ' : 'этап ') + quote(open)
      : ph.state === 'current' || ph.state === 'done' ? 'идёт · принято ' + ph.doneN + ' из ' + ph.allN + ' работ' : 'впереди · ' + ph.allN + ' работ';
    const st = a && a.state === 'rejected' ? ['cv-over', 'акт вернули'] : a && a.state === 'pending' ? ['', 'у клиента'] : a ? ['', ph.payL] : ph.state !== 'next' ? ['', 'акт — после закрытия фазы'] : ['', ''];
    const quiet = a && a.state === 'signed' && ph.pay === 'paid' && ph.payL === 'оплачено';
    return (
      <div className={'cv-drow' + (quiet ? ' is-quiet' : '') + (a && a.state !== 'signed' ? ' is-ask' : '') + (ph.state === 'next' ? ' is-next' : '')}>
        <div className="cv-drow-m">
          <span className="ic"><Ic n={a ? 'doc' : ph.state === 'next' ? 'clock' : 'tool'} s={15} c="currentColor" /></span>
          <span className="tx"><span className="t">{ph.name}</span><span className={'lab' + (a && a.state === 'rejected' ? ' is-late' : '')}>{lab}</span></span>
          <span className="num s">{rub(a ? a.amount : ph.amount)}</span>
          <span className={'st ' + st[0]}>{quiet ? '✓ ' : ''}{st[1]}</span>
        </div>
      </div>);
  }

  /* пакет сдачи объекта: что загрузить и когда (схемы — после черновых этапов своей специальности, паспорта — к финишу) */
  const HD_HINT = { scheme_electric: 'как проложен кабель: трассы, высоты, распайка', scheme_plumbing: 'трубы, коллекторы, краны и ревизии', passport: 'на технику, сантехприборы и двери' };
  function HandoverObj({ o, one, onObject, onUpload, onRemove }) {
    const [busy, setBusy] = React.useState('');
    const [err, setErr] = React.useState('');
    const pick = (kind) => (e) => {
      const list = Array.from(e.target.files || []); e.target.value = '';
      if (!list.length) return;
      setBusy(kind); setErr('');
      list.reduce((pr, f) => pr.then(() => onUpload(o.pid, kind, f)).then((r) => { if (r && r.error) throw new Error(r.error); }), Promise.resolve())
        .catch((x) => setErr(x.message || 'Файл не загрузился'))
        .then(() => setBusy(''));
    };
    const del = (id) => { const r = onRemove(o.pid, id) || {}; setErr(r.error || ''); };
    const other = o.handover.filter((d) => !o.need.some((n) => n.kind === d.kind));
    const rows = o.need.concat(other.length ? [{ kind: 'other', title: 'Другие документы', ready: true, has: other.length, after: [] }] : []);
    return (
      <div className="cv-w lw-plain lw-hobj">
        {!one && <div className="lw-mobj-h"><button type="button" className="cv-arrow-btn" onClick={() => onObject(o.pid)}>{short(o.obj)}<Ic n="ne" s={14} /></button>
          <span className="lab">загружено {o.handover.length} · гарантия {o.warranty} мес.</span></div>}
        {rows.map((n) => {
          const files = o.handover.filter((d) => (n.kind === 'other' ? other.includes(d) : d.kind === n.kind));
          return (
            <div key={n.kind} className={'lw-hrow' + (n.ready && !n.has ? ' is-ask' : '')}>
              <span className="tx"><span className="t">{n.title}</span>
                <span className="lab">{n.has ? HD_HINT[n.kind] || 'приложено к пакету' : n.ready ? 'можно загружать: ' + (n.after.length > 1 ? 'этапы ' + quote(n.after) + ' приняты' : 'этап ' + quote(n.after) + ' принят') + ' · ' + HD_HINT[n.kind]
                  : n.after.length ? 'после ' + (n.after.length > 1 ? 'этапов ' : 'этапа ') + quote(n.after) : 'в смете нет таких работ'}</span></span>
              <span className="lw-hfiles">{files.map((d) => (
                <span key={d.id} className="lw-hfile"><a href={d.url} target="_blank" rel="noopener" title={d.name || d.title}><Ic n="doc" s={14} />{String(d.name || d.title).replace(/\.[a-z0-9]{2,4}$/i, '')}</a>
                  <span className="lab">{dm(d.at)}</span>
                  <button type="button" onClick={() => del(d.id)} aria-label={'Убрать из пакета: ' + (d.name || d.title)} title="Убрать"><Ic n="x" s={13} /></button></span>))}</span>
              {n.kind !== 'other' && (n.ready || n.has) ? <label className="lw-btn-l lw-hup">{busy === n.kind ? 'Загружаем…' : n.has ? 'Ещё файл' : 'Загрузить'}
                <input type="file" accept="image/*,application/pdf" multiple hidden onChange={pick(n.kind)} disabled={!!busy} /></label> : <span />}
            </div>);
        })}
        {err && <div className="att" style={{ margin: '4px 0 12px' }}><Ic n="alert" s={16} /><span>{err}</span></div>}
      </div>);
  }

  function DocsW({ s, t0, pid, onCloseStage, onUpload, onRemove, onObject, onChat, close }) {
    const objs = s.objs.map((o) => ({ pid: o.pid, obj: o.obj }));
    const [tab, setTab] = React.useState(pid && objs.some((o) => o.pid === pid) ? pid : 'all');
    const [closed, setClosed] = React.useState([]);
    const inTab = (x) => tab === 'all' || x.pid === tab;
    const one = tab !== 'all' || objs.length === 1;
    const cl = s.close.filter(inTab), soon = s.soon.filter(inTab), pend = s.pending.filter(inTab), done = closed.filter(inTab);
    const counts = { all: s.close.length + s.pending.length }; objs.forEach((o) => { counts[o.pid] = s.close.concat(s.pending).filter((r) => r.pid === o.pid).length; });
    const closeStage = (r) => { const res = onCloseStage(r) || {}; if (!res.error) setClosed((x) => x.concat([r])); return res; };
    const waitN = pend.filter((x) => x.status === 'pending').length, backN = pend.length - waitN;
    return (
      <Modal size="wide" className="lw-sup lw-docs" title="Документы и акты" onClose={close}
        sub={[cl.length ? stages(cl.length) + ' можно закрыть' : '', waitN ? waitN + ' ' + plural(waitN, 'акт', 'акта', 'актов') + ' у клиента' : '', backN ? backN + ' вернули' : '', !cl.length && !pend.length ? 'Все акты подписаны' : ''].filter(Boolean).join(' · ')}>
        {objs.length > 1 ? <CalTabs label="Объекты" kinds={[['all', 'Все объекты']].concat(objs.map((o) => [o.pid, short(o.obj)]))} tab={tab} setTab={setTab} counts={counts} /> : null}
        <div className="cv-dlgrid lw-supg">
          <aside className="cv-dlside">
            <div className="cv-sec-h"><h2 className="h2">Закрыть этап</h2>{cl.length > 0 && <span className="lab">{cl.length}</span>}</div>
            {done.length > 0 && <ClosedCard list={done} />}
            {cl.map((r) => <CloseCard key={r.pid + r.stageId} r={r} one={one} onClose={closeStage} onObject={onObject} />)}
            {!cl.length && !done.length && <div className="cv-w cv-dlcard is-quiet"><div className="lab">Закрывать сейчас нечего. Этап можно закрыть, когда приняты все его работы: закрытие последнего этапа фазы отправит клиенту акт и счёт.</div></div>}
            {soon.length > 0 && <div className="lab lw-note lw-dsoon">Идут сейчас — закроете, когда примете все работы</div>}
            {soon.length > 0 && <div className="cv-w lw-plain lw-mlist">{soon.map((r) => (
              <div key={r.pid + r.stageId} className="lw-mrow">
                <span className="tx"><span className="t">{r.name}</span><span className="lab">{[one ? '' : short(r.obj), 'принято ' + r.doneN + ' из ' + r.works, r.review ? r.review + ' на приёмке' : ''].filter(Boolean).join(' · ')}</span></span>
                <span className="lab">до {dm(r.end)}</span>
              </div>))}</div>}

            <div className="cv-sec-h lw-sup-h"><h2 className="h2">Акты у клиента</h2>{pend.length > 0 && <span className="lab">{pend.length}</span>}</div>
            {pend.length ? <div className="cv-w lw-plain lw-mlist">{pend.map((a) => (
              <div key={a.id} className={'lw-mrow lw-arow2' + (a.status === 'rejected' ? ' is-late' : '')}>
                <span className="tx"><span className="t">{a.title.replace(/^Акт · Фаза \d+ · /, 'Акт · ')}</span>
                  <span className="lab">{[one ? '' : short(a.obj), a.status === 'rejected' ? 'вернул ' + dm(a.decidedAt) + (a.comment ? ': «' + a.comment + '»' : '') : 'отправлен ' + dm(a.since) + (a.days > 0 ? ', ' + a.days + ' ' + plural(a.days, 'день', 'дня', 'дней') + ' без ответа' : '')].filter(Boolean).join(' · ')}</span></span>
                <span className="lab">{rub(a.amount)}</span>
                {a.status === 'rejected' && onChat ? <button type="button" className="cv-arrow-btn" onClick={() => onChat(a.pid)}>Ответить в чате<Ic n="ne" s={13} /></button> : null}
              </div>))}</div>
              : <div className="cv-w cv-dlcard is-quiet"><div className="lab">Все акты подписаны. Следующий уйдёт клиенту, когда вы закроете последний этап фазы.</div></div>}
            <div className="lab lw-note">Клиент подписывает акт в своём кабинете. Пока акт не подписан и фаза не оплачена, следующая фаза не начнётся.</div>
          </aside>
          <div className="lw-supm">
            <div className="cv-sec-h"><h2 className="h2">Акты и оплаты по фазам</h2><span className="lab">счёт фазы выставляется вместе с актом</span></div>
            {s.objs.filter(inTab).map((o) => (
              <div key={o.pid} className="cv-w lw-plain lw-dph">
                {!one && <div className="lw-mobj-h"><button type="button" className="cv-arrow-btn" onClick={() => onObject(o.pid)}>{short(o.obj)}<Ic n="ne" s={14} /></button><span className="lab">смета {rub(o.total)}</span></div>}
                {o.phases.map((ph) => <PhaseRow key={ph.idx} ph={ph} open={s.close.filter((r) => r.pid === o.pid && r.phaseIdx === ph.idx).map((r) => r.name)} />)}
                <div className="cv-drow lw-dctr">
                  <div className="cv-drow-m">
                    <span className="ic"><Ic n="doc" s={15} c="currentColor" /></span>
                    <span className="tx"><span className="t">{o.contract ? o.contract.title : 'Договор'}</span>
                      <span className="lab">{o.changes.length ? o.changes.length + ' ' + plural(o.changes.length, 'допсоглашение', 'допсоглашения', 'допсоглашений') + ': ' + o.changes.map((c) => c.title + (c.status === 'pending' ? ' (у клиента)' : c.status === 'rejected' ? ' (отклонено)' : '')).join(', ') : 'допсоглашений нет'}</span></span>
                    <span className="num s">{rub(o.total)}</span>
                    <span className="st">{o.contract && o.contract.status === 'signed' ? '✓ подписан' : 'на подписании'}</span>
                  </div>
                </div>
              </div>))}
          </div>
        </div>

        <section className="lw-sec" aria-labelledby="lw-hd-h">
          <div className="lw-sech"><h2 className="h2" id="lw-hd-h">Пакет сдачи</h2><span className="lab">клиент получит его в «Приёмке объекта» вместе с гарантией</span></div>
          {s.objs.filter(inTab).map((o) => <HandoverObj key={o.pid} o={o} one={one} onObject={onObject} onUpload={onUpload} onRemove={onRemove} />)}
        </section>
      </Modal>);
  }

  W.DocsW = DocsW;
})();
