/* ============================================================
   DIRECTORY
   ============================================================ */
const NEW_PERSON = () => ({name:'', jobTitle:'', department:'', email:'', phone:'',
  employeeNumber:'', personType:'', status:'Active', location:''});

function PersonForm({value, state, onClose, onSave}){
  const [p, setP] = useState(()=>clone(value));
  const set = (k,v)=>setP(x=>({...x,[k]:v}));
  return (
    <Modal title={value.id ? 'Edit person' : 'Add person'} onClose={onClose}
      footer={<><button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn primary" disabled={!p.name.trim()} onClick={()=>onSave(p)}>Save</button></>}>
      <div className="form-grid">
        <Field label="Full name"><input type="text" value={p.name} onChange={e=>set('name',e.target.value)} autoFocus/></Field>
        <Field label="Job title"><input type="text" value={p.jobTitle||''} onChange={e=>set('jobTitle',e.target.value)}/></Field>
        <Field label="Department"><input type="text" value={p.department||''} onChange={e=>set('department',e.target.value)}/></Field>
        <Field label="Email"><input type="email" value={p.email||''} onChange={e=>set('email',e.target.value)}/></Field>
        <Field label="Phone"><input type="tel" value={p.phone||''} onChange={e=>set('phone',e.target.value)}/></Field>
        <Field label="Employee number"><input type="text" value={p.employeeNumber||''}
          onChange={e=>set('employeeNumber',e.target.value)}/></Field>
        <Field label="Type">
          <select value={p.personType||''} onChange={e=>set('personType',e.target.value)}>
            <option value="">—</option>
            {(state.lookups.person_type||[]).map(t=><option key={t}>{t}</option>)}
          </select>
        </Field>
        <Field label="Status">
          <select value={p.status||'Active'} onChange={e=>set('status',e.target.value)}>
            <option>Active</option><option>Inactive</option>
          </select>
        </Field>
        <Field label="Location"><input type="text" value={p.location||''} onChange={e=>set('location',e.target.value)}/></Field>
      </div>
    </Modal>
  );
}

function RoleForm({value, state, onClose, onSave}){
  const [r, setR] = useState(()=>clone(value));
  const set = (k,v)=>setR(x=>({...x,[k]:v}));
  return (
    <Modal title={value.id ? 'Edit role' : 'Add role'} onClose={onClose}
      footer={<><button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn primary" disabled={!r.name.trim()} onClick={()=>onSave(r)}>Save</button></>}>
      <Field label="Role name"><input type="text" value={r.name} onChange={e=>set('name',e.target.value)}
        placeholder="e.g. IT Service Desk" autoFocus/></Field>
      <Field label="Primary assignee" hint="The named individual who currently holds this role. Owner rights follow this person.">
        <select value={r.primaryPersonId||''} onChange={e=>set('primaryPersonId', e.target.value || null)}>
          <option value="">No primary assignee</option>
          {state.people.map(p=><option key={p.id} value={p.id}>{p.name} — {p.jobTitle}</option>)}
        </select>
      </Field>
      <Field label="Description"><textarea value={r.description||''} onChange={e=>set('description',e.target.value)}/></Field>
    </Modal>
  );
}

function ContactForm({value, state, onClose, onSave}){
  const [c, setC] = useState(()=>clone(value));
  const set = (k,v)=>setC(x=>({...x,[k]:v}));
  const cats = state.lookups.contact_category || ['Vendor Support'];
  return (
    <Modal title={value.id ? 'Edit contact' : 'New contact'} onClose={onClose}
      footer={<><button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn primary" disabled={!c.name.trim()} onClick={()=>onSave(c)}>Save</button></>}>
      <Field label="Contact is a">
        <div className="row" style={{gap:8}}>
          <button type="button" className={'chip-toggle'+(c.kind==='person'?' on':'')} onClick={()=>set('kind','person')}>Named individual</button>
          <button type="button" className={'chip-toggle'+(c.kind==='role'?' on':'')} onClick={()=>set('kind','role')}>Role or team</button>
        </div>
      </Field>
      <div className="form-grid">
        <Field label="Display name"><input type="text" value={c.name} onChange={e=>set('name',e.target.value)}
          placeholder={c.kind==='role' ? 'e.g. Vendor Premier Support' : 'e.g. Sandra Kelleher'} autoFocus/></Field>
        <Field label="Organisation"><input type="text" value={c.organisation||''} onChange={e=>set('organisation',e.target.value)}/></Field>
      </div>
      {c.kind === 'person' &&
        <Field label="Link to a person in the directory" hint="Optional. Use for internal contacts.">
          <select value={c.personId||''} onChange={e=>set('personId', e.target.value || null)}>
            <option value="">Not linked</option>
            {state.people.map(p=><option key={p.id} value={p.id}>{p.name}</option>)}
          </select></Field>}
      {c.kind === 'role' &&
        <Field label="Link to a role in the directory" hint="Optional. Surfaces the role's primary assignee.">
          <select value={c.roleId||''} onChange={e=>set('roleId', e.target.value || null)}>
            <option value="">Not linked</option>
            {state.roles.map(r=><option key={r.id} value={r.id}>{r.name}</option>)}
          </select></Field>}
      <div className="form-grid">
        <Field label="Category">
          <select value={c.category||''} onChange={e=>set('category',e.target.value)}>
            {cats.map(t=><option key={t}>{t}</option>)}</select></Field>
        <Field label="Hours of cover"><input type="text" value={c.hours||''}
          onChange={e=>set('hours',e.target.value)} placeholder="e.g. 24/7"/></Field>
        <Field label="Phone"><input type="tel" value={c.phone||''} onChange={e=>set('phone',e.target.value)}/></Field>
        <Field label="Email"><input type="email" value={c.email||''} onChange={e=>set('email',e.target.value)}/></Field>
      </div>
      <Field label="Support portal URL"><input type="url" value={c.portalUrl||''}
        onChange={e=>set('portalUrl',e.target.value)} placeholder="https://"/></Field>
      <Field label="Notes" hint="Contract references, response times, escalation rules.">
        <textarea value={c.notes||''} onChange={e=>set('notes',e.target.value)}/></Field>
    </Modal>
  );
}

function Directory({state, idx, go, act, tab, setTab, toast, route}){
  const [dlg, setDlg] = useState(null);
  const [viewing, setViewing] = useState(null);
  const [q, setQ] = useState(()=>urlParam('q'));
  const canEditDir = state.permissions.canEditDirectory;
  useFilterUrlSync({q:[q,'']});

  const usageOfParty = (kind, id) => accountabilitiesForParty(kind, id, state, idx);

  const peopleSort = useSort('name', {
    name: p => p.name, title: p => p.jobTitle || '', dept: p => p.department || '',
    email: p => p.email || '', involved: p => usageOfParty('person', p.id).length
  });
  const rolesSort = useSort('name', {
    name: r => r.name, primary: r => (idx.person[r.primaryPersonId]||{}).name || 'zzz',
    involved: r => usageOfParty('role', r.id).length
  });

  const TabBtn = ({k, label, n}) =>
    <button className={'tab'+(tab===k?' active':'')} onClick={()=>setTab(k)}>{label} <span className="n">{n}</span></button>;

  // One search box filters whichever tab is open, over that tab's own fields.
  const term = q.trim().toLowerCase();
  const hits = (...parts) => !term || parts.filter(Boolean).join(' ').toLowerCase().includes(term);
  const people = peopleSort.sorted(state.people.filter(p => hits(p.name, p.jobTitle, p.department, p.email, p.phone)));
  const roles = rolesSort.sorted(state.roles.filter(r =>
    hits(r.name, r.description, (idx.person[r.primaryPersonId]||{}).name)));
  const contacts = state.contacts.filter(c => hits(c.name, c.organisation, c.category, c.email, c.phone, c.hours));
  const shown = {people, roles, contacts}[tab] || [];

  const addButton = {
    people: canEditDir && {label:'Add person', dlg:{t:'person', v:NEW_PERSON()}},
    roles: canEditDir && {label:'Add role', dlg:{t:'role', v:{name:'',description:'',primaryPersonId:null}}},
    contacts: canEditDir && {label:'Add contact', dlg:{t:'contact', v:{
      kind:'role',name:'',roleId:null,personId:null,organisation:'',
      category:(state.lookups.contact_category||[])[0]||'',phone:'',email:'',portalUrl:'',hours:'',notes:''}}}
  }[tab];

  // The topbar's "Add …" button is contextual to whichever tab is open, so it
  // triggers this the same way every other module's topbar create button does.
  useEffect(()=>{
    if (route && route.action === 'new' && addButton) setDlg(addButton.dlg);
  }, [route]);

  return (
    <div className="mod">
      <div className="mod-head">
        <div className="tabs" style={{margin:0}}>
          <TabBtn k="people" label="People" n={state.people.length}/>
          <TabBtn k="roles" label="Roles" n={state.roles.length}/>
          <TabBtn k="contacts" label="Contacts" n={state.contacts.length}/>
        </div>

        {!canEditDir && <ReadOnlyBanner message="You have read-only access to the directory. Editors and administrators can make changes."/>}

        <div className="row wrap">
          <SearchBox value={q} onChange={setQ} aria="Search the directory" title="Search the open tab"/>
          {q && <button className="btn ghost sm" onClick={()=>setQ('')}>Clear</button>}
          <span className="xsmall dim">{shown.length} shown</span>
        </div>
      </div>

      <div className="mod-body">
      {tab === 'people' &&
        <div className="card">
          <div className="tbl-wrap">
            <table>
              <thead><tr>
                <peopleSort.Th k="name" label="Name"/>
                <peopleSort.Th k="title" label="Job title"/>
                <peopleSort.Th k="dept" label="Department"/>
                <peopleSort.Th k="email" label="Email"/>
                <th>Phone</th>
                <peopleSort.Th k="involved" label="Involved in"/>
                {canEditDir && <th style={{width:70}}></th>}</tr></thead>
              <tbody>{people.length === 0
                ? <tr><td colSpan={canEditDir ? 7 : 6}>
                    <EmptyState icon={<I.users size={26}/>} title="No people match"
                      action={q ? <button className="btn sm" onClick={()=>setQ('')}>Clear search</button> : null}/>
                  </td></tr>
                : people.map(p => {
                const used = usageOfParty('person', p.id);
                return (
                  <tr key={p.id} className="clickable" onClick={()=>setViewing(p.id)}>
                    <td><div className="row" style={{gap:9}}><Avatar name={p.name}/>
                      <span className="cell-name">{p.name}</span>
                      {p.status && p.status !== 'Active' && <Badge tone="slate">{p.status}</Badge>}</div></td>
                    <td className="small muted">{p.jobTitle}</td>
                    <td className="small muted">{p.department}</td>
                    <td className="small">{p.email
                      ? <a className="clink" href={'mailto:'+p.email} onClick={e=>e.stopPropagation()}><I.mail size={12}/><span>{p.email}</span></a>
                      : <span className="dim">—</span>}</td>
                    <td className="small muted">{p.phone||'—'}</td>
                    <td><Badge tone={used.length?'accent':'slate'}>{used.length} component{used.length===1?'':'s'}</Badge></td>
                    {canEditDir && <td onClick={e=>e.stopPropagation()}><div className="row" style={{gap:2}}>
                      <button className="icon-btn" onClick={()=>setDlg({t:'person', v:p})}><I.edit size={14}/></button>
                      <button className="icon-btn" onClick={()=>setDlg({t:'del-person', v:p, used})}><I.trash size={14}/></button>
                    </div></td>}
                  </tr>);
              })}</tbody>
            </table>
          </div>
        </div>}

      {tab === 'roles' &&
        <div className="card">
          <div className="card-head"><span className="xsmall dim">Each role points at a named primary assignee</span></div>
          <div className="tbl-wrap">
            <table>
              <thead><tr>
                <rolesSort.Th k="name" label="Role"/>
                <rolesSort.Th k="primary" label="Primary assignee"/>
                <th>Description</th>
                <rolesSort.Th k="involved" label="Involved in"/>
                {canEditDir && <th style={{width:70}}></th>}</tr></thead>
              <tbody>{roles.length === 0
                ? <tr><td colSpan={canEditDir ? 5 : 4}>
                    <EmptyState icon={<I.users size={26}/>} title="No roles match"
                      action={q ? <button className="btn sm" onClick={()=>setQ('')}>Clear search</button> : null}/>
                  </td></tr>
                : roles.map(r => {
                const prim = r.primaryPersonId ? idx.person[r.primaryPersonId] : null;
                const used = usageOfParty('role', r.id);
                return (
                  <tr key={r.id}>
                    <td><div className="row" style={{gap:9}}><Avatar name={r.name} kind="role"/>
                      <span className="cell-name">{r.name}</span></div></td>
                    <td>{prim
                      ? <span className="small">{prim.name}<span className="cell-sub" style={{display:'block'}}>{prim.jobTitle}</span></span>
                      : <Badge tone="amber">Vacant</Badge>}</td>
                    <td className="small muted">{r.description||'—'}</td>
                    <td><Badge tone={used.length?'accent':'slate'}>{used.length}</Badge></td>
                    {canEditDir && <td><div className="row" style={{gap:2}}>
                      <button className="icon-btn" onClick={()=>setDlg({t:'role', v:r})}><I.edit size={14}/></button>
                      <button className="icon-btn" onClick={()=>setDlg({t:'del-role', v:r, used})}><I.trash size={14}/></button>
                    </div></td>}
                  </tr>);
              })}</tbody>
            </table>
          </div>
        </div>}

      {tab === 'contacts' &&
        <div className="card">
          <div className="card-body scroll-y">
            <div className="grid" style={{gridTemplateColumns:'repeat(auto-fit,minmax(290px,1fr))',alignContent:'start'}}>
              {contacts.map(c => {
                const used = state.components.filter(x => (x.contactIds||[]).includes(c.id));
                return (
                  <div className="contact-card" key={c.id}>
                    <div className="row" style={{gap:10,alignItems:'flex-start'}}>
                      <Avatar name={c.name} kind={c.kind}/>
                      <div style={{flex:1,minWidth:0}}>
                        <div style={{fontWeight:650}}>{c.name}</div>
                        <div className="cell-sub">{c.organisation} · {c.category}</div>
                      </div>
                      {canEditDir && <>
                        <button className="icon-btn" onClick={()=>setDlg({t:'contact', v:c})}><I.edit size={14}/></button>
                        <button className="icon-btn" onClick={()=>setDlg({t:'del-contact', v:c, used})}><I.trash size={14}/></button>
                      </>}
                    </div>
                    <ContactLinks contact={c}/>
                    <div className="row" style={{marginTop:10,gap:6}}>
                      <Badge tone="slate">{used.length} component{used.length===1?'':'s'}</Badge>
                      {c.hours && <span className="xsmall dim">{c.hours}</span>}
                    </div>
                  </div>);
              })}
            </div>
            {!contacts.length &&
              <EmptyState icon={<I.phone size={28}/>} title="No contacts match"
                action={q ? <button className="btn sm" onClick={()=>setQ('')}>Clear search</button> : null}/>}
          </div>
        </div>}
      </div>

      {dlg && dlg.t === 'person' &&
        <PersonForm value={dlg.v} state={state} onClose={()=>setDlg(null)} onSave={async (v)=>{
          await act(v.id ? API.put(`/api/people/${v.id}`, v) : API.post('/api/people', v), 'Person saved');
          setDlg(null);
        }}/>}
      {dlg && dlg.t === 'role' &&
        <RoleForm value={dlg.v} state={state} onClose={()=>setDlg(null)} onSave={async (v)=>{
          await act(v.id ? API.put(`/api/roles/${v.id}`, v) : API.post('/api/roles', v), 'Role saved');
          setDlg(null);
        }}/>}
      {dlg && dlg.t === 'contact' &&
        <ContactForm value={dlg.v} state={state} onClose={()=>setDlg(null)} onSave={async (v)=>{
          await act(v.id ? API.put(`/api/contacts/${v.id}`, v) : API.post('/api/contacts', v), 'Contact saved');
          setDlg(null);
        }}/>}
      {dlg && dlg.t === 'del-person' &&
        <ConfirmDialog title="Delete person" onClose={()=>setDlg(null)}
          message={dlg.used.length
            ? `${dlg.v.name} is referenced by ${dlg.used.length} component(s). Deleting will clear those assignments.`
            : `Delete ${dlg.v.name} from the directory?`}
          onConfirm={()=>deleteWithUndo(act, toast, `/api/people/${dlg.v.id}`, dlg.v.name)}/>}
      {dlg && dlg.t === 'del-role' &&
        <ConfirmDialog title="Delete role" onClose={()=>setDlg(null)}
          message={dlg.used.length
            ? `${dlg.v.name} is referenced by ${dlg.used.length} component(s). Deleting will clear those assignments.`
            : `Delete the role ${dlg.v.name}?`}
          onConfirm={()=>deleteWithUndo(act, toast, `/api/roles/${dlg.v.id}`, dlg.v.name)}/>}
      {dlg && dlg.t === 'del-contact' &&
        <ConfirmDialog title="Delete contact" onClose={()=>setDlg(null)}
          message={`Delete ${dlg.v.name}? It will be unlinked from ${dlg.used.length} component(s).`}
          onConfirm={()=>deleteWithUndo(act, toast, `/api/contacts/${dlg.v.id}`, dlg.v.name)}/>}

      {viewing &&
        <PersonDetailModal personId={viewing} state={state} idx={idx} go={go} onClose={()=>setViewing(null)}/>}
    </div>
  );
}

function PersonDetailModal({personId, state, idx, go, onClose}){
  const p = idx.person[personId];
  if (!p) return null;
  const rows = accountabilitiesForParty('person', p.id, state, idx)
    .sort((a,b)=>a.component.name.localeCompare(b.component.name));
  return (
    <Modal title={p.name} onClose={onClose} footer={<button className="btn" onClick={onClose}>Close</button>}>
      <div className="row" style={{gap:12,alignItems:'flex-start',marginBottom:14}}>
        <Avatar name={p.name} hasAvatar={p.hasAvatar} personId={p.id} size="lg"/>
        <div style={{minWidth:0,flex:1}}>
          <div className="row wrap" style={{gap:8}}>
            <span style={{fontWeight:650,fontSize:15}}>{p.name}</span>
            <Badge tone={p.status && p.status!=='Active' ? 'slate' : 'accent'}>{p.status||'Active'}</Badge>
            {p.personType && <Badge tone="slate">{p.personType}</Badge>}
          </div>
          <div className="cell-sub">{p.jobTitle}{p.department ? ' · ' + p.department : ''}</div>
        </div>
      </div>
      <div className="side-list" style={{marginBottom:14,border:'1px solid var(--border)',borderRadius:'var(--radius-sm)'}}>
        <div className="side-row"><span className="k">Employee number</span>
          <span className="v">{p.employeeNumber || <span className="dim">—</span>}</span></div>
        <div className="side-row"><span className="k">Location</span>
          <span className="v">{p.location || <span className="dim">—</span>}</span></div>
        <div className="side-row"><span className="k">Email</span>
          <span className="v">{p.email ? <a className="clink" href={'mailto:'+p.email}>{p.email}</a> : <span className="dim">—</span>}</span></div>
        <div className="side-row"><span className="k">Phone</span>
          <span className="v">{p.phone || <span className="dim">—</span>}</span></div>
      </div>
      <div className="sub-head">Accountabilities · {rows.length}</div>
      {rows.length === 0
        ? <p className="dim small">Not currently linked to any component.</p>
        : <div className="stack" style={{gap:8}}>
            {rows.map(({component, roles}) => (
              <div className="card" key={component.id}>
                <div className="card-body">
                  <div className="row wrap" style={{gap:8}}>
                    <span className="cell-name" style={{cursor:'pointer'}}
                      onClick={()=>{ onClose(); go({view:'component', id:component.id}); }}>{component.name}</span>
                    <TierBadge tier={component.tier}/>
                  </div>
                  <div className="pill-list" style={{marginTop:6}}>
                    {roles.map((r,i)=><Badge key={i} tone={r.type==='owner'?'accent':'slate'}>{r.label}</Badge>)}
                  </div>
                </div>
              </div>
            ))}
          </div>}
    </Modal>
  );
}

