/* ============================================================
   DOCUMENTS MODULE
   ============================================================ */

/** Shared table, also used on a component's Documentation tab. `Th` is only passed
 * by the module's own list, which sorts; the embedded tab just shows plain headers. */
function DocumentTable({documents, idx, go, onUnlink, onOpen, Th}){
  const Head = Th || ((props) => {
    const rest = Object.assign({}, props);
    delete rest.k; delete rest.label;
    return <th {...rest}>{props.label}</th>;
  });
  return (
    <div className="tbl-wrap">
      <table>
        <thead><tr>
          <Head k="title" label="Document" style={{width:'34%'}}/>
          <Head k="type" label="Type"/>
          <Head k="status" label="Status"/>
          <Head k="owner" label="Owner"/>
          <Head k="version" label="Version"/>
          <Head k="review" label="Next review"/>
          <th>Components</th>{onUnlink && <th style={{width:44}}></th>}
        </tr></thead>
        <tbody>
          {documents.map(d => {
            const owner = resolveParty(d.owner, idx);
            const overdue = isOverdue(d.reviewDue) && d.status !== 'Retired';
            return (
              <tr key={d.id} className={onOpen ? 'clickable' : ''} onClick={()=>onOpen && onOpen(d)}>
                <td>
                  <div style={{fontWeight:600}}>{d.title}</div>
                  <div className="cell-sub">
                    {d.reference && <span className="mono">{d.reference} · </span>}
                    {d.summary ? d.summary.slice(0, 90) : ''}
                  </div>
                </td>
                <td><Badge tone="purple">{d.docType}</Badge></td>
                <td><Badge tone={DOC_STATUS_TONE[d.status] || 'slate'} dot>{d.status}</Badge></td>
                <td className="small">{owner
                  ? <span className="row" style={{gap:6}}><PartyAvatar resolved={owner} size="sm"/>{owner.name}</span>
                  : <span className="dim">—</span>}</td>
                <td className="small mono">{d.version || '—'}</td>
                <td className="small">
                  {d.reviewDue
                    ? <Badge tone={overdue ? 'red' : 'slate'}>{fmtDate(d.reviewDue)}</Badge>
                    : <span className="dim">—</span>}
                </td>
                <td>
                  <div className="pill-list">
                    {(d.componentIds||[]).slice(0,2).map(cid => idx.comp[cid]
                      ? <span key={cid} className="badge slate" style={{cursor:'pointer'}}
                          onClick={(e)=>{ e.stopPropagation(); go({view:'component', id:cid}); }}>
                          {idx.comp[cid].identifier}</span>
                      : null)}
                    {(d.componentIds||[]).length > 2 &&
                      <span className="badge slate">+{d.componentIds.length - 2}</span>}
                    {!(d.componentIds||[]).length && <span className="dim small">Standalone</span>}
                  </div>
                </td>
                {onUnlink && <td onClick={e=>e.stopPropagation()}>
                  <button className="icon-btn" title="Unlink from this component"
                    onClick={()=>onUnlink(d)}><I.x size={14}/></button>
                </td>}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function DocumentsModule({state, idx, go, act, toast, route}){
  const [q, setQ] = useState(()=>urlParam('q'));
  const [fType, setFType] = useState(()=>urlParam('type'));
  const [fStatus, setFStatus] = useState(()=>urlParam('status'));
  const [fScope, setFScope] = useState(()=>urlParam('scope'));
  const [fOwner, setFOwner] = useState(()=>urlParam('owner'));
  const [editing, setEditing] = useState(null);
  const [open, setOpen] = useState(null);
  const {sort, sorted, Th} = useSort('title', {
    title: d => d.title,
    type: d => d.docType,
    status: d => d.status,
    owner: d => partyName(d.owner, idx) || 'zzz',
    version: d => d.version || '',
    review: d => d.reviewDue || '9999'
  });
  useFilterUrlSync({q:[q,''], type:[fType,''], status:[fStatus,''], scope:[fScope,''], owner:[fOwner,'']});

  const canEdit = (id) => {
    const ids = state.permissions.editableDocumentIds;
    return ids === '*' || (Array.isArray(ids) && ids.includes(id));
  };
  const canCreate = state.permissions.editableDocumentIds === '*'
    || state.permissions.editableComponentIds === '*'
    || (Array.isArray(state.permissions.editableComponentIds) && state.permissions.editableComponentIds.length > 0);

  useEffect(()=>{
    if (route && route.action === 'new' && canCreate) setEditing(NEW_DOCUMENT());
  }, [route]);

  const docTypes = state.lookups.doc_type || [];
  const rows = useMemo(()=>{
    const term = q.trim().toLowerCase();
    const list = state.documents.filter(d => {
      if (fType && d.docType !== fType) return false;
      if (fStatus && d.status !== fStatus) return false;
      if (fOwner && partyKey(d.owner) !== fOwner) return false;
      if (fScope === 'standalone' && (d.componentIds||[]).length) return false;
      if (fScope === 'linked' && !(d.componentIds||[]).length) return false;
      if (fScope === 'overdue' && !(isOverdue(d.reviewDue) && d.status !== 'Retired')) return false;
      if (!term) return true;
      return [d.title, d.reference, d.summary, d.docType, d.version,
        partyName(d.owner, idx), (d.tags||[]).join(' ')].join(' ').toLowerCase().includes(term);
    });
    return sorted(list);
  }, [state.documents, q, fType, fStatus, fScope, fOwner, sort, idx]);

  const overdue = state.documents.filter(d => isOverdue(d.reviewDue) && d.status !== 'Retired');
  const soon = state.documents.filter(d => {
    const n = daysUntil(d.reviewDue);
    return n != null && n >= 0 && n <= 30 && d.status !== 'Retired';
  });

  const ownerOptions = [
    ...state.people.map(p=>({k:'person:'+p.id, label:p.name})),
    ...state.roles.map(r=>({k:'role:'+r.id, label:r.name + ' (role)'}))
  ].sort((a,b)=>a.label.localeCompare(b.label));

  const exportList = () => exportCsv('fuse-documents.csv',
    ['Reference','Title','Type','Status','Version','Owner','Last reviewed','Next review','Components','URL'],
    rows.map(d => [d.reference, d.title, d.docType, d.status, d.version, partyName(d.owner, idx),
      d.lastReviewed, d.reviewDue,
      (d.componentIds||[]).map(cid => (idx.comp[cid]||{}).identifier).filter(Boolean).join(' '),
      d.url]));

  return (
    <div className="mod">
      <div className="mod-head">
        <div className="stats-row">
          <div className="stat"><div className="n">{state.documents.length}</div><div className="l">Documents</div></div>
          <div className="stat"><div className="n">{state.documents.filter(d=>!(d.componentIds||[]).length).length}</div>
            <div className="l">Standalone</div></div>
          <div className="stat"><div className="n" style={{color: overdue.length ? 'var(--red)' : undefined}}>{overdue.length}</div>
            <div className="l">Overdue review</div></div>
          <div className="stat"><div className="n" style={{color: soon.length ? 'var(--amber)' : undefined}}>{soon.length}</div>
            <div className="l">Due in 30 days</div></div>
          <div className="stat"><div className="n">{state.documents.filter(d=>d.attachments.length).length}</div>
            <div className="l">With files</div></div>
        </div>

        <div className="row wrap">
          <div className="spacer"/>
          <button className="btn" onClick={exportList}><I.down size={14}/>CSV</button>
        </div>

        <div className="row wrap">
          <SearchBox value={q} onChange={setQ} aria="Search documents"
                     title="Search title, summary, owner or tag"/>
          <select style={{width:'auto'}} value={fType} onChange={e=>setFType(e.target.value)}>
            <option value="">All types</option>{docTypes.map(t=><option key={t}>{t}</option>)}
          </select>
          <select style={{width:'auto'}} value={fStatus} onChange={e=>setFStatus(e.target.value)}>
            <option value="">All statuses</option>
            {(state.documentStatuses||[]).map(s=><option key={s}>{s}</option>)}
          </select>
          <select style={{width:'auto'}} value={fScope} onChange={e=>setFScope(e.target.value)}>
            <option value="">Everything</option>
            <option value="linked">Linked to a component</option>
            <option value="standalone">Standalone only</option>
            <option value="overdue">Overdue review</option>
          </select>
          <select style={{width:'auto',maxWidth:200}} value={fOwner} onChange={e=>setFOwner(e.target.value)}>
            <option value="">Any owner</option>
            {ownerOptions.map(o=><option key={o.k} value={o.k}>{o.label}</option>)}
          </select>
          {(q||fType||fStatus||fScope||fOwner) &&
            <button className="btn ghost sm" onClick={()=>{setQ('');setFType('');setFStatus('');setFScope('');setFOwner('');}}>Clear</button>}
          <div className="spacer"/>
          <span className="xsmall dim">{rows.length} shown</span>
        </div>
      </div>

      <div className="mod-body">
        <div className="card">
          <div className="card-head"><span className="xsmall dim">Click a row to open</span></div>
          {rows.length
            ? <DocumentTable documents={rows} idx={idx} go={go} onOpen={setOpen} Th={Th}/>
            : <EmptyState icon={<I.book size={28}/>} title="No documents match"
                action={(q||fType||fStatus||fScope||fOwner)
                  ? <button className="btn sm" onClick={()=>{setQ('');setFType('');setFStatus('');setFScope('');setFOwner('');}}>
                      Clear filters</button>
                  : null}/>}
        </div>
      </div>

      {open &&
        <DocumentDetail doc={state.documents.find(d => d.id === open.id) || open}
          state={state} idx={idx} go={go} act={act} toast={toast}
          editable={canEdit(open.id)} onClose={()=>setOpen(null)}
          onEdit={()=>{ setEditing(state.documents.find(d => d.id === open.id)); setOpen(null); }}/>}

      {editing &&
        <DocumentForm value={editing} state={state} onClose={()=>setEditing(null)}
          onSave={async (v)=>{
            const isNew = !v.id;
            const ok = await act(isNew ? API.post('/api/documents', v) : API.put(`/api/documents/${v.id}`, v),
              isNew ? 'Document created' : 'Document saved');
            if (ok) setEditing(null);
          }}/>}
    </div>
  );
}

const NEW_DOCUMENT = () => ({
  id:'', reference:'', title:'', url:'', docType:'Reference', status:'Current', version:'',
  owner:null, lastReviewed:'', reviewDue:'', summary:'', tags:[], componentIds:[]
});

function DocumentDetail({doc, state, idx, go, act, toast, editable, onClose, onEdit}){
  const owner = resolveParty(doc.owner, idx);
  const overdue = isOverdue(doc.reviewDue) && doc.status !== 'Retired';
  const linked = (doc.componentIds||[]).map(id => idx.comp[id]).filter(Boolean);

  return (
    <Modal wide title={doc.title} onClose={onClose}
      footer={<>
        <button className="btn" onClick={onClose}>Close</button>
        {editable && <button className="btn primary" onClick={onEdit}><I.edit size={14}/>Edit</button>}
      </>}>
      <div className="row wrap" style={{gap:8, marginBottom:14}}>
        <Badge tone={DOC_STATUS_TONE[doc.status] || 'slate'} dot>{doc.status}</Badge>
        <Badge tone="purple">{doc.docType}</Badge>
        {doc.version && <Badge tone="slate">{doc.version}</Badge>}
        {overdue && <Badge tone="red">Review overdue</Badge>}
        {doc.url && <a className="btn sm" href={doc.url} target="_blank" rel="noopener noreferrer">
          <I.link size={13}/>Open document</a>}
      </div>

      {doc.summary && <p className="muted pre-wrap" style={{marginTop:0}}>{doc.summary}</p>}

      <dl className="kv-block" style={{marginTop:16}}>
        <dt>Reference</dt><dd className="mono">{doc.reference || <span className="dim">—</span>}</dd>
        <dt>Owner</dt><dd>{owner
          ? <span className="row" style={{gap:7}}><PartyAvatar resolved={owner} size="sm"/>{owner.name}
              <span className="dim small">{owner.sub}</span></span>
          : <span className="dim">Not assigned</span>}</dd>
        <dt>Last reviewed</dt><dd>{fmtDate(doc.lastReviewed) || <span className="dim">Never</span>}</dd>
        <dt>Next review</dt><dd>{doc.reviewDue
          ? <span className={overdue ? '' : 'muted'} style={overdue ? {color:'var(--red)'} : null}>
              {fmtDate(doc.reviewDue)}</span>
          : <span className="dim">Not scheduled</span>}</dd>
        <dt>Created</dt><dd className="small muted">{fmtDateTime(doc.createdAt)} by {doc.createdBy}</dd>
        <dt>Last updated</dt><dd className="small muted">{fmtDateTime(doc.updatedAt)} by {doc.updatedBy}</dd>
      </dl>

      {(doc.tags||[]).length > 0 &&
        <><div className="sub-head">Tags</div>
          <div className="pill-list">{doc.tags.map(t => <Badge key={t} tone="slate">{t}</Badge>)}</div></>}

      <div className="sub-head">Components covered</div>
      {linked.length
        ? <div className="pill-list">
            {linked.map(c =>
              <span key={c.id} className="chip-toggle" style={{cursor:'pointer'}}
                onClick={()=>{ onClose(); go({view:'component', id:c.id}); }}>
                <TierBadge tier={c.tier}/> <span style={{marginLeft:5}}>{c.name}</span></span>)}
          </div>
        : <p className="dim small" style={{margin:0}}>Standalone document, not tied to a component.</p>}

      <div style={{marginTop:18}}>
        <AttachmentPanel attachments={doc.attachments} base={`/api/documents/${doc.id}`}
          editable={editable} act={act} toast={toast} title="Files"/>
      </div>
    </Modal>
  );
}

function DocumentForm({value, state, onClose, onSave}){
  const [d, setD] = useState(()=>clone(value));
  const [tagText, setTagText] = useState((value.tags||[]).join(', '));
  const [busy, setBusy] = useState(false);
  const set = (k,v) => setD(x => ({...x, [k]:v}));
  const isNew = !value.id;
  const docTypes = state.lookups.doc_type || ['Reference'];

  return (
    <Modal wide title={isNew ? 'New document' : 'Edit ' + value.title} onClose={onClose}
      footer={<>
        <button className="btn" onClick={onClose} disabled={busy}>Cancel</button>
        <button className="btn primary" disabled={!d.title.trim() || busy}
          onClick={async ()=>{
            setBusy(true);
            try { await onSave({...d, tags: tagText.split(',').map(s=>s.trim()).filter(Boolean)}); }
            finally { setBusy(false); }
          }}>{busy ? 'Saving…' : isNew ? 'Create document' : 'Save changes'}</button>
      </>}>
      <div className="form-grid">
        <Field label="Title"><input type="text" value={d.title} autoFocus
          onChange={e=>set('title', e.target.value)} placeholder="e.g. Customer portal runbook"/></Field>
        <Field label="Reference" hint="Optional internal reference">
          <input type="text" value={d.reference} onChange={e=>set('reference', e.target.value)}/></Field>
      </div>
      <Field label="Summary"><textarea value={d.summary} onChange={e=>set('summary', e.target.value)}
        placeholder="What does this document cover, and who needs it?"/></Field>
      <Field label="URL" hint="Where it lives. Leave blank if the file is uploaded here instead.">
        <input type="url" value={d.url} onChange={e=>set('url', e.target.value)} placeholder="https://"/></Field>

      <div className="sub-head">Classification</div>
      <div className="form-grid three">
        <Field label="Type">
          <select value={d.docType} onChange={e=>set('docType', e.target.value)}>
            {docTypes.map(t => <option key={t}>{t}</option>)}</select></Field>
        <Field label="Status">
          <select value={d.status} onChange={e=>set('status', e.target.value)}>
            {(state.documentStatuses||['Current']).map(s => <option key={s}>{s}</option>)}</select></Field>
        <Field label="Version"><input type="text" value={d.version}
          onChange={e=>set('version', e.target.value)} placeholder="e.g. v3.1"/></Field>
      </div>

      <div className="sub-head">Ownership and review</div>
      <div className="form-grid three">
        <Field label="Owner"><PartySelect value={d.owner} state={state} onChange={v=>set('owner', v)}/></Field>
        <Field label="Last reviewed"><input type="date" value={d.lastReviewed}
          onChange={e=>set('lastReviewed', e.target.value)}/></Field>
        <Field label="Next review due"><input type="date" value={d.reviewDue}
          onChange={e=>set('reviewDue', e.target.value)}/></Field>
      </div>
      <Field label="Tags" hint="Comma separated"><input type="text" value={tagText}
        onChange={e=>setTagText(e.target.value)} placeholder="e.g. Mandatory reading, GDPR"/></Field>

      <div className="sub-head">Components this document covers</div>
      <ComponentPicker state={state} value={d.componentIds} onChange={v=>set('componentIds', v)}/>
      {isNew && <div className="hint" style={{marginTop:8}}>
        Leave empty for a standalone document that is not tied to anything in the Components Model.</div>}
    </Modal>
  );
}
