/* Card screens: Projects, Customers, Settings (with master-detail) */
(function () {
  const { money, fmtDate, fmtDateLong } = window.AC;

  function projectFinance(db, projectId) {
    const deliverables = new Set(
      db.projects
        .find((p) => p.id === projectId)
        ?.projectDeliverables
        .map((s) => s.id) || []
    );
    const invs = db.invoices.filter((iv) => (iv.lines || []).some((line) => line.projectId === projectId || deliverables.has(line.projectDeliverableId)));
    let billed = 0, outstanding = 0;
    invs.forEach((iv) => {
      const e = MODEL.enrich(db, iv);
      if (!MODEL.isDraft(iv) && !MODEL.isCancelled(iv)) billed += e.totals.total;
      if (e.open) outstanding += e.totals.outstanding;
    });
    return { invs, billed, outstanding };
  }

  function customerFinance(db, customerId) {
    const invs = db.invoices.filter((iv) => iv.customerId === customerId);
    let billed = 0, outstanding = 0;
    invs.forEach((iv) => {
      const e = MODEL.enrich(db, iv);
      if (!MODEL.isDraft(iv) && !MODEL.isCancelled(iv)) billed += e.totals.total;
      if (e.open) outstanding += e.totals.outstanding;
    });
    return { invs, billed, outstanding };
  }

  function ProjectTodoEditor({ plan, editing, onChange, compact }) {
    const statusOptions = window.AC.PROJECT_TODO_STATUSES;
    const categoryOptions = window.AC.PROJECT_TODO_CATEGORY_OPTIONS;
    const clusterDefaults = window.AC.PROJECT_TODO_CLUSTER_NAMES;
    const categories = (plan && plan.categories) || [];
    const categoryCount = categories.length;
    const totalItems = categories.reduce((sum, category) => sum + category.items.length, 0);
    const [remarksTarget, setRemarksTarget] = React.useState(null);
    const remarksSelection = remarksTarget && categories.reduce((found, category) => {
      if (found || category.id !== remarksTarget.categoryId) return found;
      const item = category.items.find((todo) => todo.id === remarksTarget.todoId);
      return item ? { category, item } : null;
    }, null);

    function patchPlan(nextCategories) {
      onChange({ ...plan, categories: nextCategories });
    }

    function updateCategory(categoryId, patch) {
      patchPlan(categories.map((category) => category.id === categoryId ? {
        ...category,
        ...patch,
      } : category));
    }

    function addCategory() {
      const used = new Set(categories.map((category) => category.name));
      const name = clusterDefaults.find((category) => !used.has(category)) || "General";
      patchPlan([...categories, { id: `category-${Date.now()}-${Math.random().toString(16).slice(2)}`, name, items: [] }]);
    }

    function removeCategory(categoryId) {
      patchPlan(categories.filter((category) => category.id !== categoryId));
    }

    function updateItem(categoryId, itemId, patch) {
      patchPlan(categories.map((category) => {
        if (category.id !== categoryId) return category;
        return {
          ...category,
          items: category.items.map((item) => {
            if (item.id !== itemId) return item;
            const next = { ...item, ...patch };
            if (Object.prototype.hasOwnProperty.call(patch, "done")) next.status = patch.done ? "Done" : (item.status === "Done" ? "To do" : item.status);
            if (patch.status) next.done = patch.status === "Done";
            return next;
          }),
        };
      }));
    }

    function addItem(categoryId) {
      patchPlan(categories.map((category) => category.id === categoryId ? {
        ...category,
        items: [...category.items, window.AC.newProjectTodo()],
      } : category));
    }

    function removeItem(categoryId, itemId) {
      patchPlan(categories.map((category) => category.id === categoryId ? {
        ...category,
        items: category.items.filter((item) => item.id !== itemId),
      } : category));
    }

    return (
      <div className={compact ? "todo-clusters compact" : "todo-clusters"}>
        <div className="todo-toolbar">
          <span className="muted" style={{ fontSize: 12 }}>{categoryCount} cluster{categoryCount !== 1 ? "s" : ""} · {totalItems} todo{totalItems !== 1 ? "s" : ""}</span>
          {editing && <button className="btn sm ghost" onClick={addCategory}><Icon name="plus" size={14} />Category</button>}
        </div>
        {categories.map((category) => {
          const doneCount = category.items.filter((item) => item.done).length;
          return (
            <div className="todo-cluster" key={category.id}>
              <div className="todo-cluster-head">
                {editing
                  ? <input className="inp todo-category-input" value={category.name} onChange={(event) => updateCategory(category.id, { name: event.target.value })} />
                  : <strong>{category.name}</strong>}
                <span className="chip">{doneCount}/{category.items.length} done</span>
                {editing && <button className="icon-btn" title="Add todo" onClick={() => addItem(category.id)}><Icon name="plus" size={14} /></button>}
                {editing && categories.length > 1 && <button className="icon-btn" title="Remove category" onClick={() => removeCategory(category.id)}><Icon name="trash" size={14} /></button>}
              </div>
              <div className="todo-items">
                {category.items.map((item) => (
                  <div className="todo-item" key={item.id}>
                    <div className="todo-line">
                      <input type="checkbox" title="Mark todo done" disabled={!editing} checked={!!item.done} onChange={(event) => updateItem(category.id, item.id, { done: event.target.checked })} />
                      {editing
                        ? <input className="inp" value={item.title} onChange={(event) => updateItem(category.id, item.id, { title: event.target.value })} placeholder="Todo" />
                        : <span className="todo-title" style={{ textDecoration: item.done ? "line-through" : "none" }}>{item.title || "Untitled todo"}</span>}
                      {editing
                        ? <select className="inp todo-status" value={item.status} onChange={(event) => updateItem(category.id, item.id, { status: event.target.value })}>{statusOptions.map((status) => <option key={status}>{status}</option>)}</select>
                        : <Pill kind={item.done ? "Completed" : item.status} sm />}
                      {editing && <span className="todo-actions">
                        <button className="icon-btn" title={item.remarks ? "Edit remarks" : "Add remarks"} onClick={() => setRemarksTarget({ categoryId: category.id, todoId: item.id })}><Icon name="doc" size={14} /></button>
                        <button className="icon-btn" title="Remove todo" onClick={() => removeItem(category.id, item.id)}><Icon name="trash" size={14} /></button>
                      </span>}
                    </div>
                    {editing ? (
                      <div className="todo-meta-grid">
                        <button className={'todo-remarks-trigger' + (item.remarks ? '' : ' empty')} onClick={() => setRemarksTarget({ categoryId: category.id, todoId: item.id })}>
                          <Icon name="doc" size={13} />
                          <span>{item.remarks || 'Add remarks'}</span>
                        </button>
                        <select className="inp" value={window.AC.cleanProjectTodoCategory(item.category)} onChange={(event) => updateItem(category.id, item.id, { category: event.target.value })}>
                          {categoryOptions.map((option) => <option key={option.value} value={option.value}>{option.label}</option>)}
                        </select>
                        <input className="inp" value={item.after} onChange={(event) => updateItem(category.id, item.id, { after: event.target.value })} placeholder="Continue after item X" />
                      </div>
                    ) : (item.remarks || item.after) && (
                      <div className="todo-meta">
                        {item.remarks && <span>{item.remarks}</span>}
                        {item.after && <span className="chip"><Icon name="link" size={11} />After {item.after}</span>}
                      </div>
                    )}
                  </div>
                ))}
                {category.items.length === 0 && <span className="muted" style={{ fontSize: 12 }}>No todos in this cluster.</span>}
              </div>
            </div>
          );
        })}
        <TodoRemarksDrawer
          open={!!remarksSelection}
          item={remarksSelection && remarksSelection.item}
          categoryName={remarksSelection && remarksSelection.category.name}
          onClose={() => setRemarksTarget(null)}
          onSave={(remarks) => {
            if (!remarksSelection) return;
            updateItem(remarksSelection.category.id, remarksSelection.item.id, { remarks });
            setRemarksTarget(null);
          }}
        />
      </div>
    );
  }

  window.ProjectTodoEditor = ProjectTodoEditor;

  function StatTriple({ items }) {
    return (
      <div className="rc-stats">
        {items.map((it, i) => (
          <div className="rc-stat" key={i}>
            <div className="k">{it.k}</div>
            <div className="v" style={it.tone ? { color: `var(--${it.tone})` } : null}>{it.v}</div>
          </div>
        ))}
      </div>
    );
  }

  function projectIdFromHash() {
    const match = window.location.hash.match(/^#\/?projects\/([^/]+)/);
    return match ? decodeURIComponent(match[1]) : null;
  }

  function Projects({ db, query, onDrawer, onAction, onNav, onToast, onError, onReload }) {
    const [sel, setSel] = React.useState(projectIdFromHash);
    const project = db.projects.find((p) => p.id === sel);
    const selectProject = (projectId) => {
      setSel(projectId);
      window.location.hash = projectId ? `projects/${encodeURIComponent(projectId)}` : "projects";
    };

    React.useEffect(() => {
      const syncProject = () => setSel(projectIdFromHash());
      window.addEventListener("hashchange", syncProject);
      return () => window.removeEventListener("hashchange", syncProject);
    }, []);

    if (project) return <ProjectDetailView db={db} project={project} onBack={() => selectProject(null)} onDrawer={onDrawer} onAction={onAction} onToast={onToast} onError={onError} onReload={onReload} />;

    let list = db.projects.slice();
    if (query) { const q = query.toLowerCase(); list = list.filter((p) => p.name.toLowerCase().includes(q) || (p.kind || '').toLowerCase().includes(q)); }

    return (
      <div>
        <Toolbar>
          <span className="muted" style={{ fontSize: 12 }}>{db.projects.filter((p) => p.status === 'Active').length} active · {db.projects.length} total</span>
          <div style={{ marginLeft: 'auto' }}><button className="btn" onClick={() => onDrawer('project')}><Icon name="plus" size={14} />New project</button></div>
        </Toolbar>
        <div className="project-list">
          {list.map((p) => {
            const fin = projectFinance(db, p.id);
            const pr = window.ProjectProgress(p);
            const pct = Math.round(pr.msPct * 100);
            const custNames = p.customerIds.map((id) => { const c = db.customers.find((x) => x.id === id); return c ? c.name : null; }).filter(Boolean);
            return (
              <button type="button" className="project-list-item" key={p.id} onClick={() => selectProject(p.id)}>
                <div className="project-list-main">
                  <div className="project-list-head">
                    <div className="rc-id">
                      <div className="rc-title">{p.name}</div>
                      <div className="rc-meta">{p.kind} · {p.projectDeliverables.length} deliverable{p.projectDeliverables.length !== 1 ? 's' : ''}</div>
                    </div>
                    <Pill kind={p.status} sm />
                  </div>
                  <div className="rc-meta project-list-customers">
                    <Icon name="customers" size={13} className="faint" />
                    <span>{custNames.length ? custNames.join(', ') : 'No customers linked'}</span>
                  </div>
                </div>
                <div className="project-list-progress">
                  <div className="project-progress-top">
                    <span className="project-progress-pct">{pct}%</span>
                    <span className="project-progress-label">progress</span>
                  </div>
                  <span className="progressbar"><span style={{ width: pct + '%' }} /></span>
                  <div className="project-progress-meta">
                    <span>{pr.msDone}/{pr.msTotal} milestones</span>
                    <span>{pr.todoDone}/{pr.todoTotal} todos</span>
                  </div>
                </div>
                <StatTriple items={[
                  { k: 'Billed', v: money(fin.billed) },
                  { k: 'Outstanding', v: fin.outstanding > 0 ? money(fin.outstanding) : '—', tone: fin.outstanding > 0 ? 'warn' : '' },
                  { k: 'Invoices', v: fin.invs.length },
                ]} />
              </button>
            );
          })}
        </div>
      </div>
    );
  }

  function Customers({ db, query, onDrawer, onAction, onToast, onError, onReload }) {
    const [sel, setSel] = React.useState(null);
    const customer = db.customers.find((c) => c.id === sel);
    if (customer) return <CustomerDetail db={db} customer={customer} onBack={() => setSel(null)} onDrawer={onDrawer} onAction={onAction} onToast={onToast} onError={onError} onReload={onReload} />;

    let list = db.customers.slice();
    if (query) { const q = query.toLowerCase(); list = list.filter((c) => c.name.toLowerCase().includes(q) || (c.email || '').toLowerCase().includes(q)); }

    return (
      <div>
        <Toolbar>
          <span className="muted" style={{ fontSize: 12 }}>{db.customers.length} customers</span>
          <div style={{ marginLeft: 'auto' }}><button className="btn" onClick={() => onDrawer('customer')}><Icon name="plus" size={14} />Add customer</button></div>
        </Toolbar>
        <div className="customer-list">
          {list.map((c) => {
            const fin = customerFinance(db, c.id);
            const projs = db.projects.filter((p) => p.customerIds.includes(c.id));
            const contactCount = (c.contactPersons || []).length;
            return (
              <button type="button" className="customer-list-item" key={c.id} onClick={() => setSel(c.id)}>
                <div className="customer-list-main">
                  <Avatar name={c.name} />
                  <div className="rc-id">
                    <div className="rc-title">{c.name}</div>
                    <div className="rc-meta">{c.email || c.phone || 'No contact details'}</div>
                  </div>
                  {fin.outstanding > 0 && <Pill kind="Overdue" sm>Owes</Pill>}
                </div>
                <div className="customer-list-meta">
                  <span>{projs.length} project{projs.length !== 1 ? 's' : ''}</span>
                  <span>{contactCount} contact{contactCount !== 1 ? 's' : ''}</span>
                  <span>{c.correspondence.length} note{c.correspondence.length !== 1 ? 's' : ''}</span>
                </div>
                <StatTriple items={[
                  { k: 'Billed', v: money(fin.billed) },
                  { k: 'Outstanding', v: fin.outstanding > 0 ? money(fin.outstanding) : '—', tone: fin.outstanding > 0 ? 'warn' : '' },
                  { k: 'Invoices', v: fin.invs.length },
                ]} />
              </button>
            );
          })}
        </div>
      </div>
    );
  }

  function CustomerDetail({ db, customer, onBack, onDrawer, onAction, onToast, onError, onReload }) {
    const fin = customerFinance(db, customer.id);
    const projs = db.projects.filter((p) => p.customerIds.includes(customer.id));
    const contactPersons = customer.contactPersons || [];
    const EmailComponent = window.EmailExplorer;
    return (
      <div>
        <Toolbar>
          <button className="btn subtle sm" onClick={onBack}><Icon name="chevL" size={14} />Customers</button>
          <span className="faint">/</span><span className="t-strong">{customer.name}</span>
          <div style={{ marginLeft: 'auto', display: 'flex', gap: 7 }}>
            <button className="btn ghost sm" onClick={() => onDrawer('customerContact', null, { customerId: customer.id })}><Icon name="plus" size={14} />Contact</button>
            <button className="btn ghost sm" onClick={() => onDrawer('correspondence', null, { customerId: customer.id })}><Icon name="plus" size={14} />Note</button>
            <button className="btn ghost sm" onClick={() => onDrawer('customer', customer.id)}><Icon name="edit" size={14} />Edit</button>
          </div>
        </Toolbar>
        <div className="grid" style={{ gridTemplateColumns: '1fr 1.4fr', alignItems: 'start' }}>
          <div className="grid">
            <Panel title="Profile">
              <dl className="detail-grid">
                <dt>Email</dt><dd>{customer.email || '—'}</dd>
                <dt>Phone</dt><dd>{customer.phone || '—'}</dd>
                <dt>Billing address</dt><dd style={{ whiteSpace: 'pre-line' }}>{customer.billingAddress || '—'}</dd>
                <dt>Notes</dt><dd>{customer.notes || '—'}</dd>
              </dl>
              <div className="divider" />
              <StatTriple items={[
                { k: 'Billed', v: money(fin.billed) },
                { k: 'Outstanding', v: money(fin.outstanding), tone: fin.outstanding > 0 ? 'warn' : '' },
                { k: 'Projects', v: projs.length },
              ]} />
            </Panel>
            <Panel title="Contact persons" sub={`${contactPersons.length} total`} flush>
              <DataTable
                rows={contactPersons}
                rowKey={(contact) => contact.id}
                empty="No contact persons."
                columns={[
                  { header: 'Name', render: (contact) => <div className="cellstack"><span className="t-strong">{[contact.name, contact.lastName].filter(Boolean).join(' ') || '—'}</span><span className="t-sub">{contact.remarks || '—'}</span></div> },
                  { header: 'Email', className: 'muted', render: (contact) => contact.email || '—' },
                  { header: 'Phone', className: 'muted', render: (contact) => contact.phone || '—' },
                  { header: '', className: 'num', render: (contact) => {
                    const contactName = [contact.name, contact.lastName].filter(Boolean).join(' ') || 'this contact';
                    return <span style={{ display: 'inline-flex', gap: 4 }}>
                      <button className="icon-btn" title="Edit contact" onClick={() => onDrawer('customerContact', contact.id, { customerId: customer.id })}><Icon name="edit" size={14} /></button>
                      <button className="icon-btn" title="Remove contact" onClick={() => onAction('deleteCustomerContact', { customerId: customer.id, contactId: contact.id, contactName })}><Icon name="trash" size={14} /></button>
                    </span>;
                  } },
                ]}
              />
            </Panel>
            {EmailComponent && <EmailComponent db={db} query="" onToast={onToast} onError={onError} onReload={onReload} onDrawer={onDrawer} onAction={onAction} scopeCustomer={customer} showProjectDrop={false} />}
          </div>
          <Panel title="Invoices" sub={`${fin.invs.length} total`} flush>
            <DataTable
              rows={fin.invs.sort((a, b) => b.issueDate.localeCompare(a.issueDate))}
              rowKey={(iv) => iv.id}
              empty="No invoices."
              columns={[
                { header: 'Invoice', className: 'mono t-strong', render: (iv) => iv.number },
                { header: 'Issue', className: 'mono muted', cellStyle: { fontSize: 11.5 }, render: (iv) => fmtDate(iv.issueDate) },
                { header: 'Due', className: 'mono muted', cellStyle: { fontSize: 11.5 }, render: (iv) => fmtDate(iv.dueDate) },
                { header: 'Status', render: (iv) => <Pill kind={MODEL.enrich(db, iv).display} sm /> },
                { header: 'Total', className: 'num', render: (iv) => money(MODEL.enrich(db, iv).totals.total) },
                { header: 'Outstanding', className: 'num', render: (iv) => { const e = MODEL.enrich(db, iv); return e.totals.outstanding > 0 ? money(e.totals.outstanding) : '—'; } },
              ]}
            />
          </Panel>
        </div>
      </div>
    );
  }

  function UsersSettings({ employees, onToast, onError }) {
    const empty = { name: "", email: "", password: "", role: "User", active: true, employeeId: "" };
    const [users, setUsers] = React.useState([]);
    const [form, setForm] = React.useState(empty);
    const [editId, setEditId] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
    const load = React.useCallback(async () => {
      try { setUsers(await window.API.listUsers()); }
      catch (e) { onError(e); }
      finally { setLoading(false); }
    }, [onError]);
    React.useEffect(() => { load(); }, [load]);
    const employeeById = React.useMemo(() => Object.fromEntries((employees || []).map((employee) => [employee.id, employee])), [employees]);
    const reset = () => { setEditId(null); setForm(empty); };
    const edit = (user) => {
      setEditId(user.id);
      setForm({ name: user.name, email: user.email, password: "", role: user.role, active: !!user.active, employeeId: user.employeeId || "" });
    };
    const save = async () => {
      try {
        editId ? await window.API.updateUser(editId, form) : await window.API.createUser(form);
        onToast(editId ? "User updated" : "User created");
        reset();
        await load();
      } catch (e) { onError(e); }
    };
    const remove = async (user) => {
      if (!window.confirm(`Delete ${user.email}?`)) return;
      try {
        await window.API.deleteUser(user.id);
        onToast("User deleted");
        if (editId === user.id) reset();
        await load();
      } catch (e) { onError(e); }
    };

    return (
      <Panel title="Users" sub="Application access">
        <div className="field-row">
          <div className="field"><label>Name</label><input className="inp" value={form.name} onChange={(e) => set('name', e.target.value)} /></div>
          <div className="field"><label>Email</label><input className="inp" type="email" value={form.email} onChange={(e) => set('email', e.target.value)} /></div>
        </div>
        <div className="field-row">
          <div className="field"><label>Password</label><input className="inp" type="password" value={form.password} onChange={(e) => set('password', e.target.value)} placeholder={editId ? "Leave blank to keep" : ""} /></div>
          <div className="field"><label>Role</label><select className="inp" value={form.role} onChange={(e) => set('role', e.target.value)}><option>Admin</option><option>User</option></select></div>
        </div>
        <div className="field"><label>Employee</label><select className="inp" value={form.employeeId} onChange={(e) => set('employeeId', e.target.value)}>
          <option value="">No employee</option>
          {(employees || []).map((employee) => <option key={employee.id} value={employee.id}>{employee.name}</option>)}
        </select></div>
        <label className="checkrow"><input type="checkbox" checked={form.active} onChange={(e) => set('active', e.target.checked)} /> Active</label>
        <div style={{ display: "flex", gap: 8, marginTop: 10 }}>
          <button className="btn" onClick={save}><Icon name="check" size={14} />{editId ? "Update user" : "Create user"}</button>
          {editId && <button className="btn ghost" onClick={reset}>Cancel</button>}
        </div>
        <div className="divider" />
        {loading ? <div className="muted">Loading users...</div> :
          <DataTable
            rows={users}
            rowKey={(user) => user.id}
            empty="No users."
            columns={[
              { header: "User", render: (user) => <span className="cellstack"><span className="t-strong">{user.name}</span><span className="t-sub">{user.email}</span></span> },
              { header: "Employee", render: (user) => user.employeeId && employeeById[user.employeeId] ? employeeById[user.employeeId].name : <span className="faint">None</span> },
              { header: "Role", render: (user) => <Pill kind={user.role === "Admin" ? "Open" : "Draft"}>{user.role}</Pill> },
              { header: "Status", render: (user) => <Pill kind={user.active ? "Active" : "Inactive"} sm /> },
              { header: "", className: "num", render: (user) => <span style={{ display: "inline-flex", gap: 4 }}><button className="icon-btn" title="Edit" onClick={() => edit(user)}><Icon name="edit" size={14} /></button><button className="icon-btn" title="Delete" onClick={() => remove(user)}><Icon name="trash" size={14} /></button></span> },
            ]}
          />}
      </Panel>
    );
  }

  function Settings({ db, session, onToast, onError, onSave }) {
    const s = db.settings;
    const [form, setForm] = React.useState({ ...s });
    const [emailFolders, setEmailFolders] = React.useState([]);
    const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
    const save = () => (onSave ? onSave({ ...form, currentCashBalance: Number(form.currentCashBalance) || 0, paymentTermsDays: parseInt(form.paymentTermsDays || '0', 10) }) : onToast('Settings saved'));
    const testEmail = async () => {
      try {
        const result = await window.API.testEmailConnection();
        onToast(`Email connected. Inbox: ${result.inboxCount}`);
      } catch (error) {
        onError(error);
      }
    };
    const loadEmailFolders = async () => {
      try {
        const folders = await window.API.listEmailFolders();
        setEmailFolders(folders);
        const sent = folders.find((folder) => folder.isSentCandidate && folder.selectable) || folders.find((folder) => folder.selectable);
        if (!form.emailSentFolder && sent) set('emailSentFolder', sent.fullName);
        onToast(`${folders.length} email folders found`);
      } catch (error) {
        onError(error);
      }
    };
    const isAdmin = session && session.user && session.user.role === "Admin";
    return (
      <div className="grid" style={{ gridTemplateColumns: '1.3fr 1fr', alignItems: 'start', maxWidth: 1000 }}>
        <Panel title="Company profile" sub="Appears on invoices and statements">
          <div className="field"><label>Company name</label><input className="inp" value={form.companyName} onChange={(e) => set('companyName', e.target.value)} /></div>
          <div className="field-row">
            <div className="field"><label>Legal name</label><input className="inp" value={form.legalName} onChange={(e) => set('legalName', e.target.value)} /></div>
            <div className="field"><label>Tax ID</label><input className="inp" value={form.taxId} onChange={(e) => set('taxId', e.target.value)} /></div>
          </div>
          <div className="field"><label>Address</label><textarea className="inp" value={form.address} onChange={(e) => set('address', e.target.value)} /></div>
          <div className="field"><label>Bank details</label><textarea className="inp" value={form.bankDetails} onChange={(e) => set('bankDetails', e.target.value)} /></div>
          <button className="btn" onClick={save}><Icon name="check" size={14} />Save settings</button>
        </Panel>
        <div className="grid">
          <Panel title="Billing defaults">
            <div className="field-row">
              <div className="field"><label>Currency</label><input className="inp" value={form.currency} onChange={(e) => set('currency', e.target.value)} maxLength={3} /></div>
              <div className="field"><label>Payment terms (days)</label><input className="inp num" type="number" value={form.paymentTermsDays} onChange={(e) => set('paymentTermsDays', e.target.value)} /></div>
            </div>
            <div className="field"><label>Opening cash balance</label><input className="inp num" type="number" value={form.currentCashBalance} onChange={(e) => set('currentCashBalance', e.target.value)} /></div>
            <div className="field"><label>Next invoice number</label><input className="inp num" value={form.nextInvoiceNumber} onChange={(e) => set('nextInvoiceNumber', e.target.value)} /></div>
            <div className="divider" />
            <dl className="detail-grid">
              <dt>Database</dt><dd className="mono">company-data.db</dd>
              <dt>Documents</dt><dd className="mono">/expense-documents</dd>
            </dl>
          </Panel>
          {isAdmin && <Panel title="DesignMD">
            <div className="field"><label>API URL</label><input className="inp" value={form.designMdApiUrl || ''} onChange={(e) => set('designMdApiUrl', e.target.value)} placeholder="https://designmd.ai/api/v1" /></div>
            <div className="field"><label>API key</label><input className="inp" value={form.designMdApiKey || ''} onChange={(e) => set('designMdApiKey', e.target.value)} placeholder="dk_..." /></div>
            <button className="btn" onClick={save}><Icon name="check" size={14} />Save settings</button>
          </Panel>}
          {isAdmin && <Panel title="Email account">
            <label className="checkrow"><input type="checkbox" checked={!!form.emailEnabled} onChange={(e) => set('emailEnabled', e.target.checked)} />Enable backend email access</label>
            <div className="field-row">
              <div className="field"><label>Email address</label><input className="inp" value={form.emailAddress || ''} onChange={(e) => set('emailAddress', e.target.value)} placeholder="info@appligator.de" /></div>
              <div className="field"><label>Username</label><input className="inp" value={form.emailUserName || ''} onChange={(e) => set('emailUserName', e.target.value)} placeholder="info@appligator.de" /></div>
            </div>
            <div className="field"><label>Password</label><input className="inp" type="password" value={form.emailPassword || ''} onChange={(e) => set('emailPassword', e.target.value)} placeholder="Leave unchanged" /></div>
            <div className="field-row">
              <div className="field"><label>IMAP host</label><input className="inp" value={form.emailImapHost || ''} onChange={(e) => set('emailImapHost', e.target.value)} placeholder="imap.goneo.de" /></div>
              <div className="field"><label>IMAP port</label><input className="inp num" type="number" value={form.emailImapPort || 993} onChange={(e) => set('emailImapPort', parseInt(e.target.value || '993', 10))} /></div>
            </div>
            <label className="checkrow"><input type="checkbox" checked={form.emailImapUseSsl !== false} onChange={(e) => set('emailImapUseSsl', e.target.checked)} />Use SSL for IMAP</label>
            <div className="field-row">
              <div className="field"><label>SMTP host</label><input className="inp" value={form.emailSmtpHost || ''} onChange={(e) => set('emailSmtpHost', e.target.value)} placeholder="smtp.goneo.de" /></div>
              <div className="field"><label>SMTP port</label><input className="inp num" type="number" value={form.emailSmtpPort || 465} onChange={(e) => set('emailSmtpPort', parseInt(e.target.value || '465', 10))} /></div>
            </div>
            <div className="field"><label>SMTP security</label><select className="inp" value={form.emailSmtpSecurity || 'SslOnConnect'} onChange={(e) => set('emailSmtpSecurity', e.target.value)}>
              <option value="SslOnConnect">SSL on connect</option>
              <option value="StartTls">STARTTLS</option>
              <option value="StartTlsWhenAvailable">STARTTLS when available</option>
              <option value="None">None</option>
            </select></div>
            <div className="field"><label>Sent folder</label><select className="inp" value={form.emailSentFolder || ''} onChange={(e) => set('emailSentFolder', e.target.value)}>
              <option value="">Auto-detect</option>
              {form.emailSentFolder && !emailFolders.some((folder) => folder.fullName === form.emailSentFolder) && <option value={form.emailSentFolder}>{form.emailSentFolder}</option>}
              {emailFolders.filter((folder) => folder.selectable).map((folder) => <option key={folder.fullName} value={folder.fullName}>{folder.isSentCandidate ? 'Sent: ' : ''}{folder.fullName}</option>)}
            </select></div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              <button className="btn" onClick={save}><Icon name="check" size={14} />Save settings</button>
              <button className="btn ghost" onClick={testEmail}><Icon name="mail" size={14} />Test email</button>
              <button className="btn ghost" onClick={loadEmailFolders}><Icon name="refresh" size={14} />Load folders</button>
            </div>
          </Panel>}
          {isAdmin && <UsersSettings employees={db.employees} onToast={onToast} onError={onError} />}
        </div>
      </div>
    );
  }

  function EmailExplorer({ db, query, onToast, onError, onReload, onUnreadRefresh, onDrawer, onAction, scopeId, scopeProject, scopeCustomer, showProjectDrop = true }) {
    const [messages, setMessages] = React.useState([]);
    const [scopedDrafts, setScopedDrafts] = React.useState([]);
    const [selectedKey, setSelectedKey] = React.useState(null);
    const [selected, setSelected] = React.useState(null);
    const [loading, setLoading] = React.useState(false);
    const [compose, setCompose] = React.useState(null);
    const [sending, setSending] = React.useState(false);
    const [sentConfirmation, setSentConfirmation] = React.useState("");
    const [projectsOpen, setProjectsOpen] = React.useState(false);
    const [draggedMessage, setDraggedMessage] = React.useState(null);
    const [dropTargetProjectId, setDropTargetProjectId] = React.useState(null);
    const account = (db.settings && db.settings.emailAddress) || '';
    const enabled = db.settings && db.settings.emailEnabled;
    const hasPassword = db.settings && db.settings.emailPassword;
    const scoped = !!scopeId || !!scopeCustomer;
    const scopeCustomerId = scopeCustomer && scopeCustomer.id;
    const projects = React.useMemo(() => [...(db.projects || [])].sort((a, b) => (a.name || '').localeCompare(b.name || '')), [db.projects]);
    const contactEmailOptions = React.useMemo(() => {
      const seen = new Set();
      return (db.customers || []).flatMap((customer) => (customer.contactPersons || []).map((contact) => {
        const email = String(contact.email || '').trim();
        if (!email || seen.has(email.toLowerCase())) return null;
        seen.add(email.toLowerCase());
        const name = [contact.name, contact.lastName].filter(Boolean).join(' ');
        return { email, label: [name, customer.name].filter(Boolean).join(' · ') };
      }).filter(Boolean));
    }, [db.customers]);
    const scopedEmails = React.useMemo(() => (scopeId ? ((scopeProject || projects.find((item) => item.id === scopeId) || {}).emails || []) : []).map((message) => ({
      ...message,
      itemType: 'email',
      key: `email:${message.folder}:${message.uid}`,
      folderName: message.folderName || message.folder || 'Email',
      date: message.date || new Date().toISOString(),
      attachments: [],
      isDraft: false
    })), [projects, scopeId, scopeProject]);
    const scopedDraftMessages = React.useMemo(() => scopedDrafts.map((message) => ({
      ...message,
      itemType: 'email',
      key: `email:${message.folder}:${message.uid}`,
      folderName: message.folderName || 'Draft',
      date: message.date || new Date().toISOString(),
      attachments: message.attachments || [],
      isDraft: true
    })), [scopedDrafts]);
    const scopedCorrespondence = React.useMemo(() => {
      if (!scoped) return [];
      return (db.customers || []).flatMap((customer) => (customer.correspondence || [])
        .filter((item) => scopeId ? item.projectId === scopeId : customer.id === scopeCustomerId)
        .map((item) => ({
          ...item,
          itemType: 'correspondence',
          key: `correspondence:${item.id}`,
          customerId: customer.id,
          customerName: customer.name,
          folder: 'correspondence',
          folderName: item.channel || 'Correspondence',
          uid: item.id,
          from: customer.name || 'Customer',
          to: account,
          cc: '',
          bcc: '',
          subject: item.subject,
          preview: item.body,
          textBody: item.body,
          date: item.occurredAt || item.occurredOn || item.date || new Date().toISOString(),
          attachments: [],
          isDraft: false
        })));
    }, [account, db.customers, scoped, scopeCustomerId, scopeId]);
    const sourceMessages = React.useMemo(() => scoped
      ? [...scopedDraftMessages, ...scopedEmails, ...scopedCorrespondence].sort((a, b) => new Date(b.date) - new Date(a.date))
      : messages.map((message) => ({ ...message, itemType: 'email', key: `email:${message.folder}:${message.uid}` })),
      [messages, scoped, scopedCorrespondence, scopedDraftMessages, scopedEmails]);
    const filtered = React.useMemo(() => {
      const q = String(query || '').trim().toLowerCase();
      if (!q) return sourceMessages;
      return sourceMessages.filter((message) => [message.subject, message.from, message.to, message.cc, message.folderName, message.preview, ...(message.attachments || []).map((item) => item.fileName)].join(' ').toLowerCase().includes(q));
    }, [sourceMessages, query]);
    const selectedSummary = React.useMemo(() => sourceMessages.find((message) => message.key === selectedKey) || null, [sourceMessages, selectedKey]);

    const loadInbox = React.useCallback(async () => {
      if (scoped || !enabled || !hasPassword) return;
      try {
        setLoading(true);
        const next = await window.API.listEmailMessages(50);
        setMessages(next);
        if (!selectedKey && next[0]) setSelectedKey(`email:${next[0].folder}:${next[0].uid}`);
        if (onUnreadRefresh) onUnreadRefresh();
      } catch (error) {
        onError(error);
      } finally {
        setLoading(false);
      }
    }, [enabled, hasPassword, onError, scoped, selectedKey]);

    const loadScopedDrafts = React.useCallback(async () => {
      if (!scoped) return;
      try {
        setLoading(true);
        const next = await window.API.listEmailMessages(50, { customerId: scopeCustomerId, projectId: scopeId });
        setScopedDrafts(next);
      } catch (error) {
        onError(error);
      } finally {
        setLoading(false);
      }
    }, [onError, scopeCustomerId, scopeId, scoped]);

    React.useEffect(() => { if (!scoped) loadInbox(); }, [scoped]);
    React.useEffect(() => { if (scoped) loadScopedDrafts(); }, [loadScopedDrafts, scoped]);
    React.useEffect(() => {
      if (!scoped) return;
      if (!sourceMessages.length) {
        setSelectedKey(null);
        setSelected(null);
        return;
      }
      if (!selectedKey || !sourceMessages.some((message) => message.key === selectedKey)) {
        setSelectedKey(sourceMessages[0].key);
      }
    }, [scoped, selectedKey, sourceMessages]);
    React.useEffect(() => {
      if (!selectedKey) { setSelected(null); return; }
      if (selectedSummary && selectedSummary.itemType === 'correspondence') {
        setSelected(selectedSummary);
        return;
      }

      const [, folder, uid] = selectedKey.split(':');
      let cancelled = false;
      window.API.getEmailMessage(folder, uid)
        .then((message) => { if (!cancelled) setSelected(selectedSummary ? { ...message, projectEmailId: selectedSummary.id } : message); })
        .catch((error) => { if (!cancelled) onError(error); });
      return () => { cancelled = true; };
    }, [onError, selectedKey, selectedSummary]);

    const splitAddresses = (value) => String(value || '').split(',').map((item) => item.trim()).filter(Boolean);
    const fileIcon = (attachment) => {
      const name = (attachment.fileName || '').toLowerCase();
      const type = (attachment.contentType || '').toLowerCase();
      if (type.includes('pdf') || name.endsWith('.pdf')) return 'filePdf';
      if (type.startsWith('image/') || /\.(png|jpe?g|gif|webp|svg)$/.test(name)) return 'fileImage';
      if (/\.(xls|xlsx|csv|ods)$/.test(name)) return 'fileSheet';
      if (/\.(zip|rar|7z|tar|gz)$/.test(name)) return 'fileArchive';
      return 'doc';
    };
    const formatSize = (size) => {
      if (!size) return '';
      if (size < 1024) return `${size} B`;
      if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;
      return `${(size / 1024 / 1024).toFixed(1)} MB`;
    };
    const prefixedSubject = (prefix, subject) => {
      const clean = subject || '';
      return clean.toLowerCase().startsWith(prefix.toLowerCase()) ? clean : `${prefix} ${clean}`.trim();
    };
    const quote = (message) => `\n\nOn ${new Date(message.date).toLocaleString()}, ${message.from} wrote:\n${message.textBody || message.preview || ''}`.trimEnd();
    const startCompose = (mode, message) => {
      const scopeFields = {
        customerId: (message && message.customerId) || scopeCustomerId || null,
        projectId: (message && message.projectId) || scopeId || null,
        projectDeliverableId: (message && message.projectDeliverableId) || null
      };
      if (mode === 'new' || !message) {
        setCompose({ mode: 'new', draftId: null, to: '', cc: '', bcc: '', subject: '', body: '', isHtml: false, attachments: [], replyToFolder: '', replyToUid: '', replyToMessageId: '', ...scopeFields });
      } else if (mode === 'draft') {
        setCompose({
          mode: 'draft',
          draftId: message.uid,
          to: (message.draftTo || splitAddresses(message.to)).join(', '),
          cc: (message.draftCc || splitAddresses(message.cc)).join(', '),
          bcc: (message.draftBcc || splitAddresses(message.bcc)).join(', '),
          subject: message.subject || '',
          body: message.draftBody ?? message.textBody ?? message.htmlBody ?? '',
          isHtml: !!message.draftIsHtml,
          attachments: [],
          replyToFolder: message.replyToFolder || '',
          replyToUid: message.replyToUid || '',
          replyToMessageId: message.replyToMessageId || '',
          ...scopeFields
        });
      } else if (mode === 'reply') {
        setCompose({ mode, draftId: null, to: message.from, cc: '', bcc: '', subject: prefixedSubject('Re:', message.subject), body: quote(message), isHtml: false, attachments: [], replyToFolder: message.folder, replyToUid: message.uid, replyToMessageId: message.messageId || '', ...scopeFields });
      } else if (mode === 'replyAll') {
        setCompose({ mode, draftId: null, to: message.from, cc: [message.to, message.cc].filter(Boolean).join(', '), bcc: '', subject: prefixedSubject('Re:', message.subject), body: quote(message), isHtml: false, attachments: [], replyToFolder: message.folder, replyToUid: message.uid, replyToMessageId: message.messageId || '', ...scopeFields });
      } else if (mode === 'forward') {
        setCompose({ mode, draftId: null, to: '', cc: '', bcc: '', subject: prefixedSubject('Fwd:', message.subject), body: `\n\n---------- Forwarded message ---------\nFrom: ${message.from}\nDate: ${new Date(message.date).toLocaleString()}\nSubject: ${message.subject}\nTo: ${message.to}\n\n${message.textBody || message.preview || ''}`, isHtml: false, attachments: [], replyToFolder: '', replyToUid: '', replyToMessageId: '', ...scopeFields });
      }
    };
    const composePayload = () => ({
      ...compose,
      to: splitAddresses(compose.to),
      cc: splitAddresses(compose.cc),
      bcc: splitAddresses(compose.bcc),
      customerId: compose.customerId || scopeCustomerId || null,
      projectId: compose.projectId || scopeId || null,
      projectDeliverableId: compose.projectDeliverableId || null
    });
    const saveDraft = async () => {
      if (sending) return;
      try {
        setSending(true);
        const draft = await window.API.saveEmailDraft(compose.draftId, composePayload());
        setCompose(null);
        setSelectedKey(`email:${draft.folder}:${draft.uid}`);
        onToast('Draft saved');
        scoped ? await loadScopedDrafts() : await loadInbox();
      } catch (error) {
        onError(error);
      } finally {
        setSending(false);
      }
    };
    const send = async () => {
      if (sending) return;
      try {
        setSending(true);
        const payload = composePayload();
        const result = compose.draftId
          ? await window.API.saveEmailDraft(compose.draftId, payload).then((draft) => window.API.sendEmailDraft(draft.uid, payload))
          : await window.API.sendEmail(payload);
        if (scopeId && result.sentSaved !== false && result.sentUid) {
          await window.API.attachProjectEmail(scopeId, {
            folder: 'sent',
            folderName: result.sentFolder || 'Sent',
            uid: result.sentUid,
            messageId: result.messageId || '',
            from: account,
            to: payload.to.join(', '),
            cc: payload.cc.join(', '),
            subject: payload.subject || '',
            preview: payload.body || '',
            date: new Date().toISOString()
          });
        }
        setCompose(null);
        const message = result.sentSaved === false ? (result.warning || 'Email sent, but no Sent copy was saved') : 'Email sent and saved';
        setSentConfirmation(message);
        onToast(message);
        if (scoped) {
          await loadScopedDrafts();
          if (onReload) await onReload();
        } else {
          await loadInbox();
        }
      } catch (error) {
        onError(error);
      } finally {
        setSending(false);
      }
    };
    const removeSelected = async () => {
      if (!selected || !window.confirm(`Delete "${selected.subject || '(No subject)'}"?`)) return;
      try {
        if (selected.itemType === 'correspondence') {
          await window.API.deleteCustomerCorrespondence(selected.customerId, selected.id);
        } else if (scoped && selectedSummary && selectedSummary.id) {
          await window.API.deleteProjectEmail(scopeId, selectedSummary.id);
        } else {
          await window.API.deleteEmailMessage(selected.folder, selected.uid);
        }
        setSelected(null);
        setSelectedKey(null);
        onToast(selected.itemType === 'correspondence' ? 'Correspondence deleted' : scoped ? 'Email removed from project' : 'Email deleted');
        scoped && onReload ? await onReload() : await loadInbox();
      } catch (error) {
        onError(error);
      }
    };
    const dragPayload = (message) => ({
      folder: message.folder,
      folderName: message.folderName,
      uid: message.uid,
      messageId: message.messageId,
      from: message.from,
      to: message.to,
      cc: message.cc,
      subject: message.subject,
      preview: message.preview,
      date: message.date
    });
    const startEmailDrag = (event, message) => {
      const payload = dragPayload(message);
      setDraggedMessage(payload);
      setDropTargetProjectId(null);
      event.dataTransfer.effectAllowed = 'copy';
      event.dataTransfer.setData('application/json', JSON.stringify(payload));
      event.dataTransfer.setData('text/plain', message.subject || '(No subject)');
    };
    const droppedEmail = (event) => {
      const json = event.dataTransfer.getData('application/json');
      if (json) {
        try { return JSON.parse(json); } catch (_) { }
      }

      return draggedMessage;
    };
    const attachToProject = async (event, project) => {
      event.preventDefault();
      const message = droppedEmail(event);
      if (!message || !message.folder || !message.uid) return;
        try {
          await window.API.attachProjectEmail(project.id, message);
          setDraggedMessage(null);
          setDropTargetProjectId(null);
          onToast(`Email attached to ${project.name}`);
          if (onReload) await onReload();
        } catch (error) {
        onError(error);
      }
    };
    const refreshMessages = () => scoped && onReload ? onReload() : loadInbox();

    if (!scoped && (!enabled || !hasPassword)) {
      return (
        <Panel title="Email" sub={account || 'No account configured'} actions={<button className="btn ghost" onClick={() => location.hash = '#settings'}><Icon name="settings" size={14} />Open settings</button>}>
          <Empty>Enable the email account and save its password in Settings first.</Empty>
        </Panel>
      );
    }

    return (
      <div className="grid" style={{ gridTemplateColumns: projectsOpen && showProjectDrop && !scoped ? 'minmax(280px, 360px) minmax(0, 1fr) minmax(260px, 320px)' : 'minmax(280px, 380px) minmax(0, 1fr)', alignItems: 'start', height: scoped ? 'calc(100vh - 220px)' : 'calc(100vh - 122px)' }}>
        <Panel title={scopeCustomer ? 'Customer correspondence' : scoped ? 'Project email' : (account || 'Email')} sub={loading ? 'Loading...' : `${sourceMessages.length} messages`} actions={
          <React.Fragment>
            {showProjectDrop && !scoped && <button className="icon-btn" title={projectsOpen ? 'Hide projects' : 'Attach to project'} onClick={() => setProjectsOpen(!projectsOpen)}><Icon name={projectsOpen ? 'chevR' : 'chevL'} size={15} /></button>}
            {scoped && onDrawer && <button className="icon-btn" title="Add correspondence" onClick={() => onDrawer('correspondence', null, { projectId: scopeId || '', customerId: scopeCustomerId || '' })}><Icon name="plus" size={15} /></button>}
            <button className="icon-btn" title="Refresh mail" onClick={refreshMessages}><Icon name="refresh" size={15} /></button>
          </React.Fragment>
        } flush style={{ height: '100%', overflow: 'hidden' }}>
          <div style={{ overflow: 'auto', height: '100%' }}>
            {!filtered.length && <Empty>No messages found.</Empty>}
            {filtered.map((message) => (
              <button key={message.key} draggable={message.itemType !== 'correspondence'} onDragStart={(event) => message.itemType !== 'correspondence' && startEmailDrag(event, message)} onDragEnd={() => { setDraggedMessage(null); setDropTargetProjectId(null); }} onClick={() => setSelectedKey(message.key)} style={{
                display: 'block', width: '100%', border: 0, borderBottom: '1px solid var(--line)', padding: 12, textAlign: 'left',
                background: selectedKey === message.key ? 'var(--primary-tint)' : 'transparent', cursor: message.itemType === 'correspondence' ? 'pointer' : 'grab',
                fontWeight: message.folder === 'inbox' && message.isRead === false ? 600 : 400
              }}>
                <div style={{ display: 'flex', gap: 8, justifyContent: 'space-between', alignItems: 'baseline' }}>
                  <strong style={{ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{message.isDraft ? (message.to || 'Unaddressed draft') : (message.from || 'Unknown sender')}</strong>
                  <span className="t-sub" style={{ flex: 'none' }}>{new Date(message.date).toLocaleDateString()}</span>
                </div>
                <div style={{ display: 'flex', gap: 6, alignItems: 'center', marginTop: 4 }}>
                  <Pill kind={message.itemType === 'correspondence' ? 'Draft' : message.isDraft ? 'Draft' : message.folder === 'sent' ? 'Done' : 'Open'} sm>{message.folderName}</Pill>
                  {!!(message.attachments || []).length && <Icon name="attach" size={13} />}
                  <div className="t-strong" style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{message.subject || '(No subject)'}</div>
                </div>
                <div className="t-sub" style={{ overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', marginTop: 4 }}>{message.preview}</div>
              </button>
            ))}
          </div>
        </Panel>

        <Panel title={selected ? (selected.subject || '(No subject)') : 'Message'} sub={selected ? `${selected.from} · ${new Date(selected.date).toLocaleString()}` : 'Select a message'} actions={
          <div className="actions">
            <button className="btn ghost sm" disabled={!enabled || !hasPassword} onClick={() => startCompose('new')}><Icon name="plus" size={14} />New</button>
            <button className="btn ghost sm" disabled={!selected || (!selected.isDraft && selected.itemType !== 'correspondence')} onClick={() => selected.itemType === 'correspondence' && onDrawer ? onDrawer('correspondence', selected.id, { customerId: selected.customerId, projectId: scopeId }) : startCompose('draft', selected)}><Icon name="edit" size={14} />Edit</button>
            <button className="btn ghost sm" disabled={!selected || selected.isDraft || selected.itemType === 'correspondence'} onClick={() => startCompose('reply', selected)}><Icon name="reply" size={14} />Reply</button>
            <button className="btn ghost sm" disabled={!selected || selected.isDraft || selected.itemType === 'correspondence'} onClick={() => startCompose('replyAll', selected)}><Icon name="replyAll" size={14} />Reply all</button>
            <button className="btn ghost sm" disabled={!selected || selected.isDraft || selected.itemType === 'correspondence'} onClick={() => startCompose('forward', selected)}><Icon name="forward" size={14} />Forward</button>
            <button className="btn ghost sm" disabled={!selected} onClick={removeSelected} style={{ color: 'var(--neg)' }}><Icon name="trash" size={14} />Delete</button>
          </div>
        } style={{ height: '100%', overflow: 'hidden' }}>
          {sentConfirmation && <div className="alert" style={{ marginBottom: 12, borderColor: 'rgba(22, 163, 74, .35)', background: 'rgba(22, 163, 74, .08)', color: 'var(--pos)' }}>{sentConfirmation}</div>}
          {!selected && <Empty>Select a message from the list.</Empty>}
          {selected && <div style={{ display: 'grid', gap: 12, height: '100%', overflow: 'auto' }}>
            <dl className="detail-grid">
              <dt>{selected.itemType === 'correspondence' ? 'Customer' : 'From'}</dt><dd>{selected.from}</dd>
              <dt>{selected.itemType === 'correspondence' ? 'Type' : 'To'}</dt><dd>{selected.itemType === 'correspondence' ? selected.folderName : (selected.to || <span className="faint">None</span>)}</dd>
              <dt>Cc</dt><dd>{selected.cc || <span className="faint">None</span>}</dd>
              <dt>Bcc</dt><dd>{selected.bcc || <span className="faint">None</span>}</dd>
            </dl>
            {!!(selected.attachments || []).length && <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {selected.attachments.map((attachment, index) => <span key={`${attachment.fileName}-${index}`} className="pill draft">
                <Icon name={fileIcon(attachment)} size={13} />{attachment.fileName}<span className="t-sub">{formatSize(attachment.size)}</span>
              </span>)}
            </div>}
            {selected.isDraft && <button className="btn" style={{ justifySelf: 'start' }} onClick={() => startCompose('draft', selected)}><Icon name="edit" size={14} />Edit draft</button>}
            <div style={{ whiteSpace: 'pre-wrap', lineHeight: 1.55, fontSize: 14 }}>{(selected.draftBody ?? selected.textBody) || selected.preview || 'No readable message body.'}</div>
          </div>}
        </Panel>

        {projectsOpen && showProjectDrop && !scoped && <Panel title="Projects" sub="Drop an email onto a project" flush style={{ height: '100%', overflow: 'hidden' }}>
          <div style={{ overflow: 'auto', height: '100%' }}>
            {!projects.length && <Empty>No projects found.</Empty>}
            {projects.map((project) => {
              const isDropTarget = draggedMessage && dropTargetProjectId === project.id;
              return (
                <div key={project.id} onDragEnter={() => setDropTargetProjectId(project.id)} onDragOver={(event) => { event.preventDefault(); event.dataTransfer.dropEffect = 'copy'; setDropTargetProjectId(project.id); }} onDragLeave={(event) => { if (!event.currentTarget.contains(event.relatedTarget)) setDropTargetProjectId(null); }} onDrop={(event) => attachToProject(event, project)} style={{
                  borderBottom: '1px solid var(--line)', borderLeft: isDropTarget ? '3px solid var(--primary)' : '3px solid transparent', padding: '12px 12px 12px 9px', minHeight: 76, display: 'grid', gap: 5,
                  background: isDropTarget ? 'var(--primary-tint)' : draggedMessage ? 'rgba(40, 86, 196, .06)' : 'transparent',
                  boxShadow: isDropTarget ? 'inset 0 0 0 1px rgba(40, 86, 196, .35)' : 'none'
                }}>
                  <div style={{ display: 'flex', gap: 8, justifyContent: 'space-between', alignItems: 'baseline' }}>
                    <strong style={{ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{project.name || 'Untitled project'}</strong>
                    <span className="t-sub" style={{ flex: 'none' }}>{project.status}</span>
                  </div>
                  <div className="t-sub" style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{project.kind || 'Project'}</div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    <Pill kind="Open" sm>{(project.emails || []).length} emails</Pill>
                    {!!(project.documents || []).length && <Pill kind="Draft" sm>{project.documents.length} docs</Pill>}
                  </div>
                </div>
              );
            })}
          </div>
        </Panel>}

        {compose && <div className="overlay" onClick={() => setCompose(null)} />}
        {compose && <aside className="drawer" style={{ width: 620 }}>
          <header>
            <h2>{compose.mode === 'new' ? 'New email' : compose.mode === 'draft' ? 'Draft' : compose.mode === 'forward' ? 'Forward email' : compose.mode === 'replyAll' ? 'Reply all' : 'Reply'}</h2>
            <button className="icon-btn" onClick={() => setCompose(null)}><Icon name="close" size={17} /></button>
          </header>
          <div className="body">
            <datalist id="contact-email-options">
              {contactEmailOptions.map((contact) => <option key={contact.email} value={contact.email} label={contact.label} />)}
            </datalist>
            <div className="field"><label>To</label><input className="inp" type="email" multiple list="contact-email-options" value={compose.to} onChange={(e) => setCompose({ ...compose, to: e.target.value })} /></div>
            <div className="field-row">
              <div className="field"><label>Cc</label><input className="inp" type="email" multiple list="contact-email-options" value={compose.cc} onChange={(e) => setCompose({ ...compose, cc: e.target.value })} /></div>
              <div className="field"><label>Bcc</label><input className="inp" type="email" multiple list="contact-email-options" value={compose.bcc} onChange={(e) => setCompose({ ...compose, bcc: e.target.value })} /></div>
            </div>
            <div className="field"><label>Subject</label><input className="inp" value={compose.subject} onChange={(e) => setCompose({ ...compose, subject: e.target.value })} /></div>
            <div className="field"><label>Message</label><textarea className="inp" rows="14" value={compose.body} onChange={(e) => setCompose({ ...compose, body: e.target.value })} /></div>
            <div className="field">
              <label>Attachments</label>
              <input className="inp" type="file" multiple onChange={(e) => setCompose({ ...compose, attachments: [...(compose.attachments || []), ...Array.from(e.target.files || [])] })} />
            </div>
            {!!(compose.attachments || []).length && <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {compose.attachments.map((file, index) => <button key={`${file.name}-${index}`} type="button" className="btn ghost sm" onClick={() => setCompose({ ...compose, attachments: compose.attachments.filter((_, itemIndex) => itemIndex !== index) })}>
                <Icon name={fileIcon({ fileName: file.name, contentType: file.type })} size={14} />{file.name}
              </button>)}
            </div>}
          </div>
          <footer>
            <button className="btn ghost" onClick={() => setCompose(null)}>Cancel</button>
            {sending && <span className="t-sub" style={{ marginRight: 'auto' }}>Working...</span>}
            <button className="btn ghost" disabled={sending} onClick={saveDraft}><Icon name="check" size={14} />Save draft</button>
            <button className="btn" disabled={sending} onClick={send}><Icon name={sending ? "refresh" : "mail"} size={14} />{sending ? "Sending..." : "Send"}</button>
          </footer>
        </aside>}
      </div>
    );
  }

  function Email({ db, query, onToast, onError, onReload, onUnreadRefresh }) {
    return <EmailExplorer db={db} query={query} onToast={onToast} onError={onError} onReload={onReload} onUnreadRefresh={onUnreadRefresh} />;
  }

  Object.assign(window, { Projects, Customers, Email, EmailExplorer, Settings });
})();
