/* ============================================================
   SETTINGS: my profile, quick links, data and system
   ============================================================ */

function MyProfile({state, user, refreshUser, toast, act}){
  const person = user.personId ? state.people.find(p => p.id === user.personId) : null;
  const canEditPerson = state.permissions.canEditDirectory || (person && person.id === user.personId);

  return (
    <div className="stack" style={{maxWidth:760}}>
      <div className="card">
        <div className="card-head"><h3>Your account</h3></div>
        <div className="card-body stack">
          <AvatarEditor name={user.name} endpoint={`/api/users/${user.id}/avatar`}
            hasAvatar={user.hasAvatar} toast={toast}
            onChanged={()=>refreshUser()}/>
          <div className="divider"/>
          <dl className="kv-block">
            <dt>Name</dt><dd>{user.name}</dd>
            <dt>Email</dt><dd>{user.email}</dd>
            <dt>Access level</dt><dd>
              <Badge tone={user.role==='admin'?'purple':user.role==='editor'?'accent':'slate'}>
                {ROLE_LABEL[user.role]}</Badge></dd>
            <dt>Directory record</dt><dd>{person
              ? <span>{person.name} <span className="dim small">· {person.jobTitle}</span></span>
              : <span className="dim">Not linked. Ask an administrator to link your account so that
                  ownership-based editing works.</span>}</dd>
            <dt>Last sign-in</dt><dd className="small muted">{fmtDateTime(user.lastLoginAt) || 'This session'}</dd>
          </dl>
        </div>
      </div>

      <TwoFactorSettings toast={toast}/>

      <NotificationPreferences toast={toast}/>

      {person &&
        <div className="card">
          <div className="card-head"><h3>Your directory profile</h3>
            <span className="xsmall dim">Seen by everyone across Fuse</span></div>
          <div className="card-body stack">
            <AvatarEditor name={person.name} endpoint={`/api/people/${person.id}/avatar`}
              hasAvatar={person.hasAvatar} toast={toast}
              onChanged={()=>act(Promise.resolve())}/>
            {!canEditPerson &&
              <span className="xsmall dim">Other details are maintained by an editor.</span>}
          </div>
        </div>}
    </div>
  );
}

/* ---------------------------------------------------- two-factor auth */

/** Renders a QR module matrix (from lib/core/qrcode.js) as an SVG, quiet zone included. */
function QrCode({size, modules, pixel = 5}){
  const margin = 4;
  const dim = (size + margin * 2) * pixel;
  const rects = [];
  modules.forEach((row, r) => row.forEach((dark, c) => {
    if (dark) rects.push(<rect key={r + '-' + c} x={(c + margin) * pixel} y={(r + margin) * pixel}
      width={pixel} height={pixel}/>);
  }));
  return (
    <svg width={dim} height={dim} viewBox={`0 0 ${dim} ${dim}`} shapeRendering="crispEdges">
      <rect x="0" y="0" width={dim} height={dim} fill="#fff"/>
      <g fill="#000">{rects}</g>
    </svg>
  );
}

function TwoFactorSettings({toast}){
  const [status, setStatus] = useState(null);
  const [setupDlg, setSetupDlg] = useState(null);
  const [codesDlg, setCodesDlg] = useState(null);
  const [disableDlg, setDisableDlg] = useState(null);
  const [regenDlg, setRegenDlg] = useState(null);

  const load = useCallback(async () => {
    try { setStatus(await API.get('/api/auth/2fa')); } catch { /* shown as still loading */ }
  }, []);
  useEffect(()=>{ load(); }, [load]);

  const startSetup = async () => {
    try { setSetupDlg({...(await API.post('/api/auth/2fa/setup', {})), code:'', busy:false, error:''}); }
    catch (err) { toast(err.message, true); }
  };

  const confirmSetup = async () => {
    setSetupDlg(d => ({...d, busy:true, error:''}));
    try {
      const res = await API.post('/api/auth/2fa/confirm', {code: setupDlg.code});
      setSetupDlg(null);
      setCodesDlg({codes: res.backupCodes});
      await load();
      toast('Two-factor authentication enabled');
    } catch (err) { setSetupDlg(d => ({...d, busy:false, error:err.message})); }
  };

  const disable = async () => {
    setDisableDlg(d => ({...d, busy:true, error:''}));
    try {
      await API.post('/api/auth/2fa/disable', {password: disableDlg.password});
      setDisableDlg(null);
      await load();
      toast('Two-factor authentication disabled');
    } catch (err) { setDisableDlg(d => ({...d, busy:false, error:err.message})); }
  };

  const regenerate = async () => {
    setRegenDlg(d => ({...d, busy:true, error:''}));
    try {
      const res = await API.post('/api/auth/2fa/backup-codes', {password: regenDlg.password});
      setRegenDlg(null);
      setCodesDlg({codes: res.backupCodes});
      await load();
      toast('Backup codes regenerated');
    } catch (err) { setRegenDlg(d => ({...d, busy:false, error:err.message})); }
  };

  return (
    <div className="card">
      <div className="card-head"><h3>Two-factor authentication</h3>
        {status && <Badge tone={status.enabled ? 'green' : 'slate'} dot>{status.enabled ? 'Enabled' : 'Disabled'}</Badge>}
      </div>
      <div className="card-body stack">
        {!status && <div className="row" style={{gap:10}}><span className="spinner"/>Loading…</div>}
        {status && !status.enabled &&
          <>
            <p className="muted small" style={{margin:0}}>
              Add a second step to sign-in with an authenticator app — Google Authenticator, 1Password,
              Authy or similar.
            </p>
            <div><button className="btn primary" onClick={startSetup}>
              <I.shield size={14}/>Set up two-factor authentication</button></div>
          </>}
        {status && status.enabled &&
          <>
            <dl className="kv-block">
              <dt>Backup codes remaining</dt><dd>{status.backupCodesRemaining}</dd>
            </dl>
            <div className="row wrap" style={{gap:8}}>
              <button className="btn sm" onClick={()=>setRegenDlg({password:'', busy:false, error:''})}>
                Regenerate backup codes</button>
              <button className="btn sm danger" onClick={()=>setDisableDlg({password:'', busy:false, error:''})}>
                Disable</button>
            </div>
          </>}
      </div>

      {setupDlg &&
        <Modal title="Set up two-factor authentication" onClose={()=>setSetupDlg(null)}
          footer={<>
            <button className="btn" onClick={()=>setSetupDlg(null)}>Cancel</button>
            <button className="btn primary" disabled={setupDlg.busy || setupDlg.code.length < 6}
              onClick={confirmSetup}>{setupDlg.busy ? 'Verifying…' : 'Verify and enable'}</button>
          </>}>
          {setupDlg.error && <div className="err">{setupDlg.error}</div>}
          <div className="stack" style={{gap:16}}>
            <div>
              <p className="small muted" style={{marginTop:0}}>
                Scan this with your authenticator app, or enter the secret manually if it can’t scan.
              </p>
              <div className="qr-frame"><QrCode size={setupDlg.qr.size} modules={setupDlg.qr.modules}/></div>
              <div className="row" style={{gap:8, alignItems:'center', marginTop:10}}>
                <code className="mono small" style={{wordBreak:'break-all'}}>{setupDlg.secret}</code>
                <button className="icon-btn" title="Copy secret"
                  onClick={()=>{ navigator.clipboard.writeText(setupDlg.secret); toast('Secret copied'); }}>
                  <I.paper size={14}/></button>
              </div>
            </div>
            <Field label="Enter the 6-digit code from your app">
              <input type="text" inputMode="numeric" autoFocus value={setupDlg.code}
                onChange={e=>setSetupDlg(d=>({...d, code:e.target.value}))} placeholder="123456"/>
            </Field>
          </div>
        </Modal>}

      {codesDlg &&
        <Modal title="Save your backup codes" onClose={()=>setCodesDlg(null)}
          footer={<button className="btn primary" onClick={()=>setCodesDlg(null)}>Done</button>}>
          <div className="warn-box" style={{marginBottom:14}}>
            Each code works once, to get back in if you lose access to your authenticator app. Store
            them somewhere safe — they will not be shown again.
          </div>
          <div className="backup-codes">{codesDlg.codes.map(c => <code key={c}>{c}</code>)}</div>
          <div style={{marginTop:14}}>
            <button className="btn sm"
              onClick={()=>download('fuse-backup-codes.txt', codesDlg.codes.join('\n'), 'text/plain')}>
              <I.down size={13}/>Download codes</button>
          </div>
        </Modal>}

      {disableDlg &&
        <Modal title="Disable two-factor authentication" onClose={()=>setDisableDlg(null)}
          footer={<>
            <button className="btn" onClick={()=>setDisableDlg(null)}>Cancel</button>
            <button className="btn danger" disabled={disableDlg.busy || !disableDlg.password}
              onClick={disable}>{disableDlg.busy ? 'Disabling…' : 'Disable'}</button>
          </>}>
          {disableDlg.error && <div className="err">{disableDlg.error}</div>}
          <Field label="Confirm your password">
            <input type="password" autoFocus value={disableDlg.password}
              onChange={e=>setDisableDlg(d=>({...d, password:e.target.value}))}/>
          </Field>
        </Modal>}

      {regenDlg &&
        <Modal title="Regenerate backup codes" onClose={()=>setRegenDlg(null)}
          footer={<>
            <button className="btn" onClick={()=>setRegenDlg(null)}>Cancel</button>
            <button className="btn primary" disabled={regenDlg.busy || !regenDlg.password}
              onClick={regenerate}>{regenDlg.busy ? 'Working…' : 'Regenerate'}</button>
          </>}>
          {regenDlg.error && <div className="err">{regenDlg.error}</div>}
          <div className="warn-box" style={{marginBottom:14}}>Your existing backup codes will stop working.</div>
          <Field label="Confirm your password">
            <input type="password" autoFocus value={regenDlg.password}
              onChange={e=>setRegenDlg(d=>({...d, password:e.target.value}))}/>
          </Field>
        </Modal>}
    </div>
  );
}

/* ------------------------------------------------------------ quick links */

const QUICK_ICON_CHOICES = ['link','tool','plus','grid','book','inbox','chart','users','shield','warn','graph','note','key'];

function QuickLinksAdmin({state, act}){
  const [dlg, setDlg] = useState(null);
  const empty = {label:'', target:'', icon:'link', groupLabel:'Quick links', description:''};
  const groups = {};
  state.quickLinks.forEach(q => { (groups[q.groupLabel] = groups[q.groupLabel] || []).push(q); });

  return (
    <div className="stack" style={{maxWidth:900}}>
      <div className="info-box">
        {'Quick links appear in everyone’s sidebar. Use them for the forms and saved views people ' +
         'reach for most. A target starting with #/ stays inside Fuse; a full web address opens ' +
         'in a new tab.'}
      </div>
      <div className="card">
        <div className="card-head"><h3>Quick links</h3><Badge tone="slate">{state.quickLinks.length}</Badge>
          <div className="spacer"/>
          <button className="btn sm primary" onClick={()=>setDlg({v:{...empty}})}>
            <I.plus size={13}/>Add quick link</button></div>
        {state.quickLinks.length === 0
          ? <EmptyState icon={<I.link size={28}/>} title="No quick links yet"
              body="Add shortcuts to the forms and views your colleagues use most."/>
          : <div>
              {Object.keys(groups).sort().map(g => (
                <div key={g}>
                  <div className="sub-head" style={{padding:'12px 16px 6px',margin:0,
                    background:'var(--surface-2)',borderTop:'1px solid var(--border)',
                    borderBottom:'1px solid var(--border)'}}>{g}</div>
                  {groups[g].map(q => {
                    const Icon = I[q.icon] || I.link;
                    return (
                      <div className="link-row" key={q.id}>
                        <span style={{color:'var(--text-3)'}}><Icon size={16}/></span>
                        <div style={{flex:1,minWidth:0}}>
                          <div style={{fontWeight:600}}>{q.label}</div>
                          <div className="link-url">{q.target}</div>
                          {q.description && <div className="xsmall muted">{q.description}</div>}
                        </div>
                        <button className="icon-btn" onClick={()=>setDlg({v:q})}><I.edit size={14}/></button>
                        <button className="icon-btn" title="Delete"
                          onClick={()=>act(API.del(`/api/quick-links/${q.id}`), 'Quick link removed')}>
                          <I.trash size={14}/></button>
                      </div>
                    );
                  })}
                </div>
              ))}
            </div>}
      </div>

      {dlg && <QuickLinkForm value={dlg.v} onClose={()=>setDlg(null)}
        onSave={async (v)=>{
          const ok = await act(v.id ? API.put(`/api/quick-links/${v.id}`, v) : API.post('/api/quick-links', v),
            'Quick link saved');
          if (ok) setDlg(null);
        }}/>}
    </div>
  );
}

function QuickLinkForm({value, onClose, onSave}){
  const [q, setQ] = useState(()=>clone(value));
  const set = (k,v) => setQ(x => ({...x, [k]:v}));
  const Icon = I[q.icon] || I.link;
  return (
    <Modal title={value.id ? 'Edit quick link' : 'Add quick link'} onClose={onClose}
      footer={<>
        <button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn primary" disabled={!q.label.trim() || !q.target.trim()}
          onClick={()=>onSave(q)}>Save</button>
      </>}>
      <div className="form-grid">
        <Field label="Label"><input type="text" value={q.label} autoFocus
          onChange={e=>set('label', e.target.value)} placeholder="e.g. Raise a request"/></Field>
        <Field label="Group" hint="Links are grouped by this heading">
          <input type="text" value={q.groupLabel} onChange={e=>set('groupLabel', e.target.value)}
            placeholder="e.g. Forms"/></Field>
      </div>
      <Field label="Target" hint="#/requests/new for an internal page, or an https:// address">
        <input type="text" value={q.target} onChange={e=>set('target', e.target.value)}
          placeholder="#/requests/new"/></Field>
      <Field label="Description"><input type="text" value={q.description}
        onChange={e=>set('description', e.target.value)}/></Field>
      <Field label="Icon">
        <div className="row wrap" style={{gap:6}}>
          {QUICK_ICON_CHOICES.map(name => {
            const Choice = I[name];
            return (
              <button key={name} type="button" className={'chip-toggle' + (q.icon===name ? ' on' : '')}
                onClick={()=>set('icon', name)} title={name}><Choice size={14}/></button>
            );
          })}
        </div>
      </Field>
      <div className="row" style={{gap:9,marginTop:6,padding:'10px 12px',
        border:'1px solid var(--border)',borderRadius:'var(--radius-sm)',background:'var(--surface-2)'}}>
        <Icon size={16}/><strong style={{fontSize:13}}>{q.label || 'Preview'}</strong>
      </div>
    </Modal>
  );
}

/* ---------------------------------------------------------- data & system */

/** Bulk CSV imports for every module that supports one, gathered in one place so
 * the module toolbars stay focused on finding and creating single records. */
const CSV_IMPORTS = [
  {k:'people', label:'People', endpoint:'/api/people', title:'Import people from CSV',
   permission:(p)=>p.canEditDirectory, fields:()=>IMPORT_PEOPLE_FIELDS,
   hint:'Names, job titles, departments and contact details for the directory.'},
  {k:'components', label:'Components', endpoint:'/api/components', title:'Import components from CSV',
   permission:(p)=>p.canCreateComponents, fields:(state)=>componentImportFields(state),
   hint:'Systems, services and the rest of the estate, with type, tier and owners.'},
  {k:'tools', label:'Tools & services', endpoint:'/api/tools', title:'Import tools & services from CSV',
   permission:(p)=>p.editableToolIds === '*', fields:()=>IMPORT_TOOL_FIELDS,
   hint:'Consoles, portals and dashboards, optionally linked to a component.'}
];

function DataSettings({state, act, toast}){
  const [confirm, setConfirm] = useState(null);
  const [phrase, setPhrase] = useState('');
  const [system, setSystem] = useState(null);
  const [importing, setImporting] = useState(null);
  const [jobsList, setJobsList] = useState(null);
  const isAdmin = state.permissions.isAdmin;
  const imports = CSV_IMPORTS.filter(i => i.permission(state.permissions));

  useEffect(()=>{
    if (!isAdmin) return;
    API.get('/api/admin/system').then(setSystem).catch(()=>{});
    API.get('/api/jobs').then(r=>setJobsList(r.jobs)).catch(()=>{});
  }, [isAdmin]);

  const counts = [
    ['Components', state.components.length],
    ['Relationships', state.dependencies.length],
    ['Changes', state.changes.length],
    ['Approval templates', state.approvalTemplates.length],
    ['Tools & services', state.tools.length],
    ['Tool links', state.tools.reduce((s,t)=>s+(t.links||[]).length,0)],
    ['Documents', state.documents.length],
    ['Business requests', state.requests.length],
    ['Reports', state.reports.length],
    ['People', state.people.length],
    ['Roles', state.roles.length],
    ['Contacts', state.contacts.length],
    ['RACI assignments', state.components.reduce((s,c)=>s+(c.raci||[]).length,0)],
    ['Notes', state.components.reduce((s,c)=>s+(c.componentNotes||[]).length,0)],
    ['Attachments', state.components.reduce((s,c)=>s+c.attachments.length,0)
      + state.documents.reduce((s,d)=>s+d.attachments.length,0)
      + state.requests.reduce((s,r)=>s+r.attachments.length,0)]
  ];

  const exportJson = async () => {
    try {
      const data = await API.get('/api/export');
      download('fuse-' + todayIso() + '.json', JSON.stringify(data, null, 2));
      toast('Export downloaded');
    } catch (err) { toast(err.message, true); }
  };

  return (
    <div className="stack" style={{maxWidth:860}}>
      <div className="info-box">
        {'Everything lives in the server’s SQLite database, with uploaded files and profile images ' +
         'alongside it in the data directory. Back up that directory to back up all of Fuse.'}
      </div>

      <div className="card">
        <div className="card-head"><h3>Export</h3></div>
        <div className="card-body">
          <p className="muted small" style={{marginTop:0}}>
            A full JSON snapshot of every module. Uploaded files are not included — copy the data
            directory for those.
          </p>
          <button className="btn" onClick={exportJson}><I.down size={14}/>Export all data (JSON)</button>
        </div>
      </div>

      {imports.length > 0 &&
        <div className="card">
          <div className="card-head"><h3>Import from CSV</h3></div>
          <div className="side-list">
            {imports.map(imp =>
              <div className="side-row" key={imp.k}>
                <span className="k" style={{minWidth:0}}>
                  <span style={{display:'block',fontWeight:600,color:'var(--text)'}}>{imp.label}</span>
                  <span className="xsmall">{imp.hint}</span>
                </span>
                <span className="v">
                  <button className="btn sm" onClick={()=>setImporting(imp)}>
                    <I.up size={13}/>Import</button>
                </span>
              </div>)}
          </div>
        </div>}

      {importing &&
        <ImportCsvModal title={importing.title} fields={importing.fields(state)} toast={toast}
          onImportRow={(values)=>API.post(importing.endpoint, values)}
          onDone={()=>act(Promise.resolve())}
          onClose={()=>setImporting(null)}/>}

      <div className="card">
        <div className="card-head"><h3>Contents</h3></div>
        <div className="side-list">
          {counts.map(([k,v]) =>
            <div className="side-row" key={k}><span className="k">{k}</span><span className="v mono">{v}</span></div>)}
        </div>
      </div>

      {system &&
        <div className="card">
          <div className="card-head"><h3>System</h3></div>
          <div className="side-list">
            <div className="side-row"><span className="k">Node</span><span className="v mono">{system.node}</span></div>
            <div className="side-row"><span className="k">Modules</span>
              <span className="v small">{system.modules.join(', ')}</span></div>
            <div className="side-row"><span className="k">Migrations applied</span>
              <span className="v mono">{system.migrations.length}</span></div>
            <div className="side-row"><span className="k">Database</span>
              <span className="v mono">{fmtBytes(system.storage.databaseBytes)}</span></div>
            <div className="side-row"><span className="k">Uploaded files</span>
              <span className="v mono">{fmtBytes(system.storage.uploadBytes)}</span></div>
            <div className="side-row"><span className="k">Profile images</span>
              <span className="v mono">{fmtBytes(system.storage.avatarBytes)}</span></div>
            <div className="side-row"><span className="k">Uptime</span>
              <span className="v mono">{Math.floor(system.uptimeSeconds/3600)}h {Math.floor(system.uptimeSeconds/60)%60}m</span></div>
          </div>
        </div>}

      {isAdmin && jobsList && jobsList.length > 0 &&
        <div className="card">
          <div className="card-head"><h3>Background jobs</h3>
            <span className="xsmall dim">Recurring server-side tasks — the same list any future ones will join</span></div>
          <div className="side-list">
            {jobsList.map(j =>
              <div className="side-row" key={j.name}>
                <span className="k" style={{minWidth:0}}>
                  <span style={{display:'block',fontWeight:600,color:'var(--text)'}}>{j.name}</span>
                  <span className="xsmall dim">Last ran {relative(j.startedAt)}
                    {j.detail ? ' — ' + j.detail : ''}</span>
                </span>
                <span className="v"><Badge tone={j.status === 'ok' ? 'green' : 'red'}>{j.status}</Badge></span>
              </div>)}
          </div>
        </div>}

      {isAdmin &&
        <div className="card">
          <div className="card-head"><h3>Administration</h3></div>
          <div className="card-body stack">
            <div className="row wrap">
              <button className="btn" disabled={state.components.length > 0}
                title={state.components.length ? 'Only available on an empty installation' : ''}
                onClick={()=>setConfirm('seed')}>Load demo data</button>
              <button className="btn danger" onClick={()=>{ setPhrase(''); setConfirm('clear'); }}>
                Clear everything</button>
            </div>
            <span className="xsmall dim">
              Clearing removes every component, document, request, report, relationship and uploaded
              file, plus the whole directory. User accounts and classification lists are kept.
            </span>
          </div>
        </div>}

      {confirm === 'seed' &&
        <ConfirmDialog title="Load demo data" confirmLabel="Load demo data"
          message="This loads the built-in sample dataset across every module: 21 components, 42 documents, 16 business requests and 8 reports."
          onClose={()=>setConfirm(null)}
          onConfirm={()=>act(API.post('/api/admin/load-demo', {}), 'Demo data loaded')}/>}

      {confirm === 'clear' &&
        <Modal title="Clear everything" onClose={()=>setConfirm(null)}
          footer={<>
            <button className="btn" onClick={()=>setConfirm(null)}>Cancel</button>
            <button className="btn danger" disabled={phrase !== 'DELETE EVERYTHING'}
              onClick={async ()=>{
                const ok = await act(API.post('/api/admin/clear', {confirm: phrase}), 'Everything cleared');
                if (ok) setConfirm(null);
              }}>Delete everything</button>
          </>}>
          <div className="warn-box" style={{marginBottom:16}}>
            This permanently deletes {state.components.length} components, {state.documents.length} documents,
            {' '}{state.requests.length} requests, {state.reports.length} reports, the whole directory
            and every uploaded file. Export a backup first if you need one.
          </div>
          <Field label="Type DELETE EVERYTHING to confirm">
            <input type="text" value={phrase} onChange={e=>setPhrase(e.target.value)} autoFocus/>
          </Field>
        </Modal>}
    </div>
  );
}
