// Surface — Organisations & roles
//
// Split out of the old combined Roles surface (see §25.14). This page owns
// ONLY the DEFINITION side:
//   · create / rename / recolour / delete organisations (each shown as a
//     module in the page body — see §25.10),
//   · create / rename / delete roles,
//   · assign each role to an organisation (role → org mapping).
// The content-binding matrix (roles ↔ modules / assessment questions) lives
// on its own "Content mapping" surface — never on this page.
//
// MODEL (§25.10): there is NO grouping toggle. Organisations are created
// from the page-header "Add organisation" button and render as modules in
// the body. "Grouped" is derived purely from `brands.length > 0`. The
// schema flag `course.selectBrand` (Player <selectBrand> tag) maps to
// "are there any organisations?" — it is never a UI control here.

function SurfaceOrgRoles({ roles: rolesIn, course, startBlank }) {
  const [brands, setBrands] = React.useState(startBlank ? [] : (course.brands || []));
  const [roles, setRoles] = React.useState(startBlank ? [] : rolesIn);
  const [roleCfg, setRoleCfg] = React.useState(() =>
    Object.fromEntries((startBlank ? [] : rolesIn).map(r => [r.code, { label: r.label, brand: r.brand }])));
  const [focusRole, setFocusRole] = React.useState(null);

  // Grouping is derived, not toggled: any organisation → grouped view.
  const grouped = brands.length > 0;

  // ── Organisation mutators ───────────────────────────────────────────────
  const addBrand = () => {
    const id = 'b' + Date.now().toString(36);
    const palette = ['#5C2D91', '#1B2A3D', '#0F766E', '#B91C1C', '#B45309', '#1D4ED8'];
    const color = palette[brands.length % palette.length];
    setBrands(bs => [...bs, { id, label: 'New organisation', color, textColor: '#ffffff' }]);
  };
  const updateBrand = (id, patch) =>
    setBrands(bs => bs.map(b => b.id === id ? { ...b, ...patch } : b));
  const removeBrand = (id) => {
    setBrands(bs => bs.filter(b => b.id !== id));
    // Roles on the removed org reset to null and drop into the "No
    // organisation" module — never silently moved elsewhere.
    setRoleCfg(c => {
      const next = { ...c };
      Object.keys(next).forEach(code => {
        if (next[code].brand === id) next[code] = { ...next[code], brand: null };
      });
      return next;
    });
  };

  // ── Role mutators ────────────────────────────────────────────────────────
  // brandId === undefined → unassigned (lands in "No organisation").
  // The page-header "Add role" NEVER auto-assigns to an organisation; only
  // an organisation module's own "Add role" passes its brand id (§25.10).
  const addRole = (brandId = null) => {
    const code = 'r' + Date.now().toString(36);
    setRoles(rs => [...rs, { code, label: 'New role', brand: brandId }]);
    setRoleCfg(c => ({ ...c, [code]: { label: 'New role', brand: brandId } }));
    setFocusRole(code);
  };
  const updateRole = (code, patch) =>
    setRoleCfg(c => ({ ...c, [code]: { ...c[code], ...patch } }));
  const removeRole = (code) => {
    setRoles(rs => rs.filter(r => r.code !== code));
    setRoleCfg(c => { const n = { ...c }; delete n[code]; return n; });
  };

  // ── Bands: one module per organisation + a trailing "No organisation" ─────
  const bands = React.useMemo(() => {
    if (!grouped) return [{ brand: null, roles }];
    const out = brands.map(b => ({
      brand: b, roles: roles.filter(r => roleCfg[r.code]?.brand === b.id),
    }));
    const unassigned = roles.filter(r => {
      const b = roleCfg[r.code]?.brand;
      return !brands.some(x => x.id === b);
    });
    // Always show the "No organisation" module when grouped — it is the
    // landing spot for header-added roles and the reassignment source.
    out.push({
      brand: { id: '__none', label: 'No organisation', color: 'var(--border-strong)' },
      roles: unassigned,
    });
    return out;
  }, [grouped, brands, roles, roleCfg]);

  const empty = roles.length === 0 && brands.length === 0;

  return (
    <div data-screen-label="Surface · Organisations & roles" style={{
      display: 'flex', flexDirection: 'column', height: '100%', background: 'var(--bg)',
    }}>
      <OrgRolesHeader onAddRole={() => addRole()} onAddOrganisation={addBrand} />

      <div style={{ flex: 1, overflowY: 'auto', padding: '20px 24px 40px' }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {empty ? (
            <EmptyRolesState onAddRole={() => addRole()} onAddOrganisation={addBrand} />
          ) : (
            <React.Fragment>
              {bands.map(({ brand, roles: bandRoles }) => (
                <RoleBand key={brand ? brand.id : '_all'}
                  brand={brand} grouped={grouped} roles={bandRoles}
                  brands={brands} roleCfg={roleCfg} focusRole={focusRole}
                  onAddRole={() => addRole(brand && brand.id !== '__none' ? brand.id : null)}
                  onUpdateRole={updateRole} onRemoveRole={removeRole}
                  onUpdateBrand={updateBrand} onRemoveBrand={removeBrand} />
              ))}
              <p style={{ margin: '2px 2px 0', fontSize: 11.5, color: 'var(--text-faint)',
                display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <I.Globe size={11} />Role names are translated in Localisation › Roles.
              </p>
            </React.Fragment>
          )}
        </div>
      </div>
    </div>
  );
}

// ── Page header ─────────────────────────────────────────────────────────────
function OrgRolesHeader({ onAddRole, onAddOrganisation }) {
  return (
    <header style={{
      padding: '20px 24px 16px', borderBottom: '1px solid var(--border)',
      background: 'var(--surface)', display: 'flex', alignItems: 'flex-end', gap: 14,
    }}>
      <div style={{ flex: 1 }}>
        <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>Organisations &amp; roles</h2>
        <p style={{ margin: '4px 0 0', fontSize: 12.5, color: 'var(--text-muted)', maxWidth: 680 }}>
          Define the audiences for this course and, optionally, the organisations they belong to.
          Decide <em>what</em> each role sees over in <strong>Content mapping</strong>.
        </p>
      </div>
      <button className="btn sm" onClick={onAddOrganisation}
        title="Add an organisation. Roles can be assigned to it, or left unassigned.">
        <I.Plus size={12} />Add organisation
      </button>
      <button className="btn sm primary" onClick={onAddRole}>
        <I.Plus size={12} />Add role
      </button>
    </header>
  );
}

// ── RoleBand · one organisation module (or the flat list) ────────────────────
function RoleBand({ brand, grouped, roles, brands, roleCfg, focusRole,
  onAddRole, onUpdateRole, onRemoveRole, onUpdateBrand, onRemoveBrand }) {
  const isNone = brand && brand.id === '__none';
  const isOrg = grouped && brand && !isNone;
  return (
    <div style={{ background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--radius-md)', overflow: 'hidden' }}>
      {grouped && (
        isOrg ? (
          <OrgBandHeader brand={brand} count={roles.length}
            onUpdate={patch => onUpdateBrand(brand.id, patch)}
            onRemove={() => onRemoveBrand(brand.id)}
            onAddRole={onAddRole} hasRoles={roles.length > 0} />
        ) : (
          <div style={{ display: 'flex', alignItems: 'center', gap: 10,
            padding: '10px 14px', borderBottom: roles.length ? '1px solid var(--border)' : 0,
            background: 'var(--surface-inset)' }}>
            <span style={{ width: 12, height: 12, borderRadius: 3, flexShrink: 0,
              background: brand.color, border: '1px dashed var(--border-strong)' }} />
            <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-muted)' }}>{brand.label}</span>
            <span className="pill" style={{ fontSize: 10 }}>{roles.length}</span>
            <div style={{ flex: 1 }} />
            <button className="btn sm ghost" onClick={onAddRole}>
              <I.Plus size={11} />Add role
            </button>
          </div>
        )
      )}

      {roles.length === 0 ? (
        <div style={{ padding: '14px', fontSize: 12, color: 'var(--text-faint)' }}>
          {isNone ? 'No unassigned roles. New roles added from the header land here.'
            : 'No roles in this organisation yet.'}
        </div>
      ) : (
        roles.map(r => (
          <RoleRow key={r.code} role={r} cfg={roleCfg[r.code]} grouped={grouped}
            brands={brands} autoFocus={focusRole === r.code}
            onUpdate={patch => onUpdateRole(r.code, patch)}
            onRemove={() => onRemoveRole(r.code)} />
        ))
      )}

      {!grouped && (
        <div style={{ padding: '10px 14px', borderTop: roles.length ? '1px solid var(--border)' : 0 }}>
          <button className="btn sm ghost" onClick={onAddRole}>
            <I.Plus size={11} />Add role
          </button>
        </div>
      )}
    </div>
  );
}

// ── OrgBandHeader · organisation module header: colour + rename + add + delete
function OrgBandHeader({ brand, count, onUpdate, onRemove, onAddRole, hasRoles }) {
  const [editing, setEditing] = React.useState(false);
  const [draft, setDraft] = React.useState(brand.label);
  React.useEffect(() => { setDraft(brand.label); }, [brand.label]);
  const commit = () => { onUpdate({ label: draft.trim() || brand.label }); setEditing(false); };
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10,
      padding: '10px 14px', borderBottom: hasRoles ? '1px solid var(--border)' : 0,
      background: 'var(--surface-inset)' }}>
      {/* Colour swatch — native colour input disguised as a chip */}
      <label style={{ position: 'relative', width: 14, height: 14, borderRadius: 4,
        background: brand.color, border: '1px solid rgba(0,0,0,.12)',
        cursor: 'default', display: 'inline-block', flexShrink: 0 }}
        title="Click to change the organisation colour">
        <input type="color" value={brand.color}
          onChange={(e) => onUpdate({ color: e.target.value })}
          style={{ position: 'absolute', inset: 0, opacity: 0, cursor: 'default',
            width: '100%', height: '100%' }} />
      </label>
      {editing ? (
        <input autoFocus value={draft}
          onChange={(e) => setDraft(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => {
            if (e.key === 'Enter') commit();
            if (e.key === 'Escape') { setDraft(brand.label); setEditing(false); }
          }}
          style={{ border: 0, outline: 0, background: 'transparent', font: 'inherit',
            fontSize: 13, fontWeight: 600, width: Math.max(80, draft.length * 8),
            color: 'var(--text)' }} />
      ) : (
        <button onClick={() => setEditing(true)} title="Rename organisation" style={{
          border: 0, background: 'transparent', font: 'inherit', padding: 0,
          fontSize: 13, fontWeight: 600, color: 'var(--text)', cursor: 'default' }}>
          {brand.label}
        </button>
      )}
      <span className="pill" style={{ fontSize: 10 }}>{count}</span>
      <div style={{ flex: 1 }} />
      <button className="btn sm ghost" onClick={onAddRole}>
        <I.Plus size={11} />Add role
      </button>
      <button className="btn sm ghost danger" onClick={onRemove}
        title="Delete organisation. Its roles move to “No organisation”."
        style={{ width: 28, padding: 0, justifyContent: 'center' }}>
        <I.Trash size={12} />
      </button>
    </div>
  );
}

// ── RoleRow · editable name + organisation assignment + delete ───────────────
function RoleRow({ role, cfg, grouped, brands, autoFocus, onUpdate, onRemove }) {
  const inputRef = React.useRef(null);
  React.useEffect(() => { if (autoFocus && inputRef.current) inputRef.current.select(); }, [autoFocus]);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px',
      borderBottom: '1px solid var(--border-faint)' }}>
      <I.User size={14} style={{ color: 'var(--text-faint)', flexShrink: 0 }} />
      <input ref={inputRef} className="field" value={cfg.label}
        onChange={e => onUpdate({ label: e.target.value })}
        placeholder="e.g. Manager"
        style={{ flex: 1, minWidth: 0, maxWidth: 340, fontWeight: 500 }} />
      <div style={{ flex: 1 }} />
      {grouped && (
        <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
          <I.Tag size={12} style={{ color: 'var(--text-faint)' }} />
          <select className="field select-elegant" value={cfg.brand || ''}
            onChange={e => onUpdate({ brand: e.target.value || null })}
            style={{ paddingRight: 28, minWidth: 168 }}>
            <option value="">No organisation</option>
            {brands.map(b => <option key={b.id} value={b.id}>{b.label}</option>)}
          </select>
        </label>
      )}
      <button className="btn sm ghost danger" onClick={onRemove}
        title="Delete role" style={{ width: 28, padding: 0, justifyContent: 'center' }}>
        <I.Trash size={12} />
      </button>
    </div>
  );
}

// ── EmptyRolesState · blank page · both actions, no funnel ───────────────────
function EmptyRolesState({ onAddRole, onAddOrganisation }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center',
      justifyContent: 'center', gap: 14, padding: '60px 24px', textAlign: 'center',
      color: 'var(--text-muted)', background: 'var(--surface)',
      border: '1px solid var(--border)', borderRadius: 'var(--radius-md)' }}>
      <I.Users size={32} style={{ color: 'var(--text-faint)' }} />
      <div>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>
          No roles or organisations yet
        </h3>
        <p style={{ margin: '6px auto 0', fontSize: 12.5, maxWidth: 420, lineHeight: 1.5 }}>
          Add a role to define an audience for this course. Add an organisation to
          group roles — roles can stay unassigned until you decide.
        </p>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <button className="btn sm" onClick={onAddOrganisation}>
          <I.Plus size={12} />Add organisation
        </button>
        <button className="btn sm primary" onClick={onAddRole}>
          <I.Plus size={12} />Add the first role
        </button>
      </div>
    </div>
  );
}

Object.assign(window, { SurfaceOrgRoles });
