// workspace-forms.jsx — общие формы сотрудников, отделов и должностей

const DEPT_COLORS = [
  'dept-blue', 'dept-violet', 'dept-amber', 'dept-green', 'dept-rose', 'dept-slate',
];

const PICKER_TONES = ['folder-blue', 'folder-amber', 'folder-violet', 'folder-green'];
const DEPT_COLOR_TONE = {
  'dept-blue': 'folder-blue',
  'dept-green': 'folder-green',
  'dept-violet': 'folder-violet',
  'dept-amber': 'folder-amber',
  'dept-rose': 'folder-violet',
  'dept-slate': 'folder-blue',
};

const deptTone = (dept, depth = 0) => DEPT_COLOR_TONE[dept?.color] || PICKER_TONES[depth % PICKER_TONES.length];

const useFixedPickerMenu = (open, anchorRef) => {
  const [style, setStyle] = React.useState(null);
  React.useLayoutEffect(() => {
    if (!open || !anchorRef.current) {
      setStyle(null);
      return undefined;
    }
    const update = () => {
      const el = anchorRef.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const gap = 6;
      const maxH = 280;
      const below = window.innerHeight - r.bottom - gap - 16;
      const above = r.top - gap - 16;
      const openUp = below < 140 && above > below;
      const avail = Math.max(120, openUp ? above : below);
      setStyle({
        position: 'fixed',
        left: `${Math.round(r.left)}px`,
        width: `${Math.round(r.width)}px`,
        top: openUp ? 'auto' : `${Math.round(r.bottom + gap)}px`,
        bottom: openUp ? `${Math.round(window.innerHeight - r.top + gap)}px` : 'auto',
        maxHeight: `${Math.min(maxH, avail)}px`,
      });
    };
    update();
    window.addEventListener('resize', update);
    window.addEventListener('scroll', update, true);
    return () => {
      window.removeEventListener('resize', update);
      window.removeEventListener('scroll', update, true);
    };
  }, [open, anchorRef]);
  return style;
};

const PickerShell = ({
  open,
  setOpen,
  isEmpty,
  triggerIcon,
  triggerIconClass,
  triggerText,
  children,
}) => {
  const wrapRef = React.useRef(null);
  const menuRef = React.useRef(null);
  const menuStyle = useFixedPickerMenu(open, wrapRef);

  React.useEffect(() => {
    if (!open) return undefined;
    const close = (e) => {
      if (wrapRef.current?.contains(e.target) || menuRef.current?.contains(e.target)) return;
      setOpen(false);
    };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [open, setOpen]);

  const menu = open && menuStyle && ReactDOM.createPortal(
    <div
      ref={menuRef}
      className="section-picker-menu section-picker-menu--overlay"
      style={menuStyle}
      role="listbox"
    >
      {children}
    </div>,
    document.body,
  );

  return (
    <>
      <div className={`section-picker section-picker--overlay${open ? ' is-open' : ''}`} ref={wrapRef}>
        <button
          type="button"
          className={`section-picker-trigger${isEmpty ? ' is-empty' : ''}`}
          onClick={() => setOpen((v) => !v)}
          aria-expanded={open}
        >
          <span className={`section-picker-trigger-icon ${triggerIconClass || ''}`}>
            <Icon name={triggerIcon} size={15} />
          </span>
          <span className="section-picker-trigger-text">{triggerText}</span>
          <Icon name="chevronDown" size={14} className="section-picker-trigger-chevron" />
        </button>
      </div>
      {menu}
    </>
  );
};

const DepartmentTreePicker = ({ value, onChange, placeholder = '— не выбран —', excludeId = null }) => {
  const [open, setOpen] = React.useState(false);
  const flat = (window.getDepartmentsFlat?.() || []).filter((d) => d.id !== excludeId);
  const selected = value ? window.findDepartment(value) : null;
  const pathParts = value ? window.getDepartmentPathParts?.(value) || [] : [];
  const lid = window.LEADERSHIP_DEPT_ID;
  const trimmedParts = pathParts.length > 1 && pathParts[0]?.id === lid ? pathParts.slice(1) : pathParts;

  const triggerText = trimmedParts.length
    ? trimmedParts.map((d, i) => (
      <React.Fragment key={d.id}>
        {i > 0 && <span className="section-picker-trigger-sep">/</span>}
        <span>{d.name}</span>
      </React.Fragment>
    ))
    : placeholder;

  const pick = (id) => {
    onChange(id || '');
    setOpen(false);
  };

  return (
    <PickerShell
      open={open}
      setOpen={setOpen}
      isEmpty={!selected}
      triggerIcon="folder"
      triggerIconClass={selected ? deptTone(selected, trimmedParts.length - 1) : ''}
      triggerText={triggerText}
    >
      <button
        type="button"
        className={`section-picker-item section-picker-item--empty${!value ? ' is-selected' : ''}`}
        style={{ '--sp-depth': 0 }}
        onClick={() => pick('')}
      >
        <span className="section-picker-item-indent" />
        <span className="section-picker-item-icon section-picker-item-icon--muted">
          <Icon name="folder" size={14} />
        </span>
        <span className="section-picker-item-name">{placeholder}</span>
        {!value && <Icon name="check" size={14} className="section-picker-item-check" />}
      </button>
      {flat.map((d) => {
        const dept = window.findDepartment(d.id);
        const isSelected = value === d.id;
        return (
          <button
            key={d.id}
            type="button"
            className={`section-picker-item${isSelected ? ' is-selected' : ''}`}
            style={{ '--sp-depth': d.depth }}
            onClick={() => pick(d.id)}
          >
            <span className="section-picker-item-indent" aria-hidden="true">
              {d.depth > 0 && <span className="section-picker-item-branch" />}
            </span>
            <span className={`section-picker-item-icon ${deptTone(dept, d.depth)}`}>
              <Icon name="folder" size={14} />
            </span>
            <span className="section-picker-item-name">{d.name}</span>
            {isSelected && <Icon name="check" size={14} className="section-picker-item-check" />}
          </button>
        );
      })}
    </PickerShell>
  );
};

const ParentPositionTreePicker = ({ value, onChange, excludeId, placeholder = '— верхний уровень (без руководителя) —' }) => {
  const [open, setOpen] = React.useState(false);
  const groups = window.groupPositionsForParentPick?.(excludeId) || [];
  const primaryByPos = window.getPrimaryPeopleByPosition?.() || new Map();
  const selected = value ? window.findPosition(value) : null;
  const dept = selected ? window.findDepartment(selected.departmentId) : null;
  const deptLabel = selected ? window.getDepartmentDisplayPath(selected.departmentId) : '';

  const triggerText = selected ? (
    <>
      {deptLabel && (
        <>
          <span>{deptLabel}</span>
          <span className="section-picker-trigger-sep">/</span>
        </>
      )}
      <span>{selected.name}</span>
    </>
  ) : placeholder;

  const pick = (id) => {
    onChange(id || '');
    setOpen(false);
  };

  const positionLabel = (p, headId) => {
    const person = primaryByPos.get(p.id);
    const parts = [p.name];
    if (person?.name) parts.push(person.name);
    return parts.join(' · ');
  };

  return (
    <PickerShell
      open={open}
      setOpen={setOpen}
      isEmpty={!selected}
      triggerIcon={selected ? 'user' : 'org'}
      triggerIconClass={dept ? deptTone(dept) : ''}
      triggerText={triggerText}
    >
      <button
        type="button"
        className={`section-picker-item section-picker-item--empty${!value ? ' is-selected' : ''}`}
        style={{ '--sp-depth': 0 }}
        onClick={() => pick('')}
      >
        <span className="section-picker-item-indent" />
        <span className="section-picker-item-icon section-picker-item-icon--muted">
          <Icon name="org" size={14} />
        </span>
        <span className="section-picker-item-name">{placeholder}</span>
        {!value && <Icon name="check" size={14} className="section-picker-item-check" />}
      </button>
      {groups.map((g) => (
        <React.Fragment key={g.deptId || '_none'}>
          <div
            className="section-picker-item section-picker-item--header"
            style={{ '--sp-depth': 0 }}
            aria-hidden="true"
          >
            <span className="section-picker-item-indent" />
            <span className={`section-picker-item-icon ${deptTone(window.findDepartment(g.deptId))}`}>
              <Icon name="folder" size={14} />
            </span>
            <span className="section-picker-item-name">{g.label}</span>
          </div>
          {g.tree.map(({ position: p, depth }) => {
            const isSelected = value === p.id;
            const isHead = g.headId === p.id;
            const parent = depth > 0 ? window.findPosition(p.parentPositionId) : null;
            return (
              <button
                key={p.id}
                type="button"
                className={`section-picker-item${isSelected ? ' is-selected' : ''}${isHead ? ' section-picker-item--head' : ''}`}
                style={{ '--sp-depth': 1 + depth }}
                onClick={() => pick(p.id)}
              >
                <span className="section-picker-item-indent" aria-hidden="true">
                  {depth > 0 && <span className="section-picker-item-branch" />}
                </span>
                <span className={`section-picker-item-icon ${isHead ? 'section-picker-item-icon--head' : 'section-picker-item-icon--role'}`}>
                  <Icon name={isHead ? 'org' : 'user'} size={14} />
                </span>
                <span className="section-picker-item-label">
                  <span className="section-picker-item-name">{positionLabel(p, g.headId)}</span>
                  {isHead ? (
                    <span className="section-picker-item-meta">руководитель отдела</span>
                  ) : parent ? (
                    <span className="section-picker-item-meta">подчиняется «{parent.name}»</span>
                  ) : null}
                </span>
                {isSelected && <Icon name="check" size={14} className="section-picker-item-check" />}
              </button>
            );
          })}
        </React.Fragment>
      ))}
    </PickerShell>
  );
};

const PositionAssignPicker = ({
  value,
  onChange,
  allowedIds,
  placeholder = '— выберите должность —',
  emptyHint = 'Сначала создайте должность в настройках или на схеме',
}) => {
  const [open, setOpen] = React.useState(false);
  const groups = window.groupPositionsForAssign?.(allowedIds) || [];
  const primaryByPos = window.getPrimaryPeopleByPosition?.() || new Map();
  const selected = value ? window.findPosition(value) : null;
  const dept = selected ? window.findDepartment(selected.departmentId) : null;
  const deptLabel = selected ? window.getDepartmentDisplayPath(selected.departmentId) : '';

  const triggerText = selected ? (
    <>
      {deptLabel && (
        <>
          <span>{deptLabel}</span>
          <span className="section-picker-trigger-sep">/</span>
        </>
      )}
      <span>{selected.name}</span>
    </>
  ) : placeholder;

  const pick = (id) => {
    onChange(id || '');
    setOpen(false);
  };

  const positionLabel = (p) => {
    const person = primaryByPos.get(p.id);
    const parts = [p.name];
    if (person?.name) parts.push(person.name);
    else parts.push('вакантно');
    return parts.join(' · ');
  };

  return (
    <PickerShell
      open={open}
      setOpen={setOpen}
      isEmpty={!selected}
      triggerIcon={selected ? 'user' : 'org'}
      triggerIconClass={dept ? deptTone(dept) : ''}
      triggerText={groups.length ? triggerText : '— нет должностей —'}
    >
      {!groups.length ? (
        <div className="section-picker-item section-picker-item--empty" style={{ '--sp-depth': 0 }}>
          <span className="section-picker-item-indent" />
          <span className="section-picker-item-name">{emptyHint}</span>
        </div>
      ) : (
        <>
          <button
            type="button"
            className={`section-picker-item section-picker-item--empty${!value ? ' is-selected' : ''}`}
            style={{ '--sp-depth': 0 }}
            onClick={() => pick('')}
          >
            <span className="section-picker-item-indent" />
            <span className="section-picker-item-icon section-picker-item-icon--muted">
              <Icon name="org" size={14} />
            </span>
            <span className="section-picker-item-name">{placeholder}</span>
            {!value && <Icon name="check" size={14} className="section-picker-item-check" />}
          </button>
          {groups.map((g) => (
            <React.Fragment key={g.deptId || '_none'}>
              <div
                className="section-picker-item section-picker-item--header"
                style={{ '--sp-depth': 0 }}
                aria-hidden="true"
              >
                <span className="section-picker-item-indent" />
                <span className={`section-picker-item-icon ${deptTone(window.findDepartment(g.deptId))}`}>
                  <Icon name="folder" size={14} />
                </span>
                <span className="section-picker-item-name">{g.label}</span>
              </div>
              {g.tree.map(({ position: p, depth }) => {
                const isSelected = value === p.id;
                const isHead = g.headId === p.id;
                const vacant = !primaryByPos.has(p.id);
                return (
                  <button
                    key={p.id}
                    type="button"
                    className={`section-picker-item${isSelected ? ' is-selected' : ''}${isHead ? ' section-picker-item--head' : ''}`}
                    style={{ '--sp-depth': 1 + depth }}
                    onClick={() => pick(p.id)}
                  >
                    <span className="section-picker-item-indent" aria-hidden="true">
                      {depth > 0 && <span className="section-picker-item-branch" />}
                    </span>
                    <span className={`section-picker-item-icon ${isHead ? 'section-picker-item-icon--head' : 'section-picker-item-icon--role'}`}>
                      <Icon name={isHead ? 'org' : 'user'} size={14} />
                    </span>
                    <span className="section-picker-item-label">
                      <span className="section-picker-item-name">{positionLabel(p)}</span>
                      <span className="section-picker-item-meta">
                        {p.workspaceRoleName || '—'}{vacant ? ' · вакантно' : ''}
                      </span>
                    </span>
                    {isSelected && <Icon name="check" size={14} className="section-picker-item-check" />}
                  </button>
                );
              })}
            </React.Fragment>
          ))}
        </>
      )}
    </PickerShell>
  );
};

const ROLE_ICONS = { admin: 'lock', editor: 'edit', viewer: 'eye' };

const RoleListPicker = ({ value, onChange, roles, placeholder = '— выберите роль —' }) => {
  const [open, setOpen] = React.useState(false);
  const selected = roles.find((r) => r.id === value) || null;

  const pick = (id) => {
    onChange(id || '');
    setOpen(false);
  };

  return (
    <PickerShell
      open={open}
      setOpen={setOpen}
      isEmpty={!selected}
      triggerIcon={selected ? (ROLE_ICONS[selected.slug] || 'lock') : 'lock'}
      triggerIconClass={selected ? 'section-picker-item-icon--role' : ''}
      triggerText={selected?.name || placeholder}
    >
      <button
        type="button"
        className={`section-picker-item section-picker-item--empty${!value ? ' is-selected' : ''}`}
        style={{ '--sp-depth': 0 }}
        onClick={() => pick('')}
      >
        <span className="section-picker-item-indent" />
        <span className="section-picker-item-icon section-picker-item-icon--muted">
          <Icon name="lock" size={14} />
        </span>
        <span className="section-picker-item-name">{placeholder}</span>
        {!value && <Icon name="check" size={14} className="section-picker-item-check" />}
      </button>
      {roles.map((role) => {
        const isSelected = value === role.id;
        return (
          <button
            key={role.id}
            type="button"
            className={`section-picker-item${isSelected ? ' is-selected' : ''}`}
            style={{ '--sp-depth': 0 }}
            onClick={() => pick(role.id)}
          >
            <span className="section-picker-item-indent" />
            <span className="section-picker-item-icon section-picker-item-icon--role">
              <Icon name={ROLE_ICONS[role.slug] || 'lock'} size={14} />
            </span>
            <span className="section-picker-item-name">{role.name}</span>
            {isSelected && <Icon name="check" size={14} className="section-picker-item-check" />}
          </button>
        );
      })}
    </PickerShell>
  );
};

const AVATARS = ['av-1', 'av-2', 'av-3', 'av-4', 'av-5', 'av-6', 'av-7', 'av-8'];

const SettingsModal = ({ title, onClose, children, wide }) => (
  <div className="settings-modal-backdrop" onClick={onClose}>
    <div
      className={`settings-modal${wide ? ' settings-modal--wide' : ''}`}
      onClick={(e) => e.stopPropagation()}
    >
      <div className="settings-modal-head">
        <h3>{title}</h3>
        <button type="button" className="topbar-icon-btn" onClick={onClose} aria-label="Закрыть">
          ×
        </button>
      </div>
      <div className="settings-modal-body">{children}</div>
    </div>
  </div>
);

const ManagerPersonPicker = ({ value, onChange, excludeId, placeholder = '— верхний уровень (владелец) —' }) => {
  const [open, setOpen] = React.useState(false);
  const people = (window.getActivePeople?.() || []).filter((p) => p.id !== excludeId);
  const selected = people.find((p) => p.id === value);
  const flatDepts = window.getDepartmentsFlat?.() || [];
  const deptLabel = (p) => {
    const path = window.getDepartmentDisplayPath?.(p.departmentId);
    return path || p.dept || '—';
  };

  const triggerText = selected
    ? `${selected.name}${deptLabel(selected) ? ` · ${deptLabel(selected)}` : ''}`
    : placeholder;

  return (
    <PickerShell
      open={open}
      setOpen={setOpen}
      isEmpty={!selected}
      triggerIcon="user"
      triggerText={triggerText}
    >
      <button
        type="button"
        className={`section-picker-item section-picker-item--empty${!value ? ' is-selected' : ''}`}
        style={{ '--sp-depth': 0 }}
        onClick={() => { onChange(''); setOpen(false); }}
      >
        <span className="section-picker-item-indent" />
        <span className="section-picker-item-icon section-picker-item-icon--muted">
          <Icon name="org" size={14} />
        </span>
        <span className="section-picker-item-name">{placeholder}</span>
        {!value && <Icon name="check" size={14} className="section-picker-item-check" />}
      </button>
      {flatDepts.map((d) => {
        const inDept = people.filter((p) => p.departmentId === d.id);
        if (!inDept.length) return null;
        return (
          <React.Fragment key={d.id}>
            <div className="section-picker-item section-picker-item--header" style={{ '--sp-depth': d.depth }}>
              <span className="section-picker-item-indent" />
              <span className={`section-picker-item-icon ${deptTone(window.findDepartment(d.id))}`}>
                <Icon name="folder" size={14} />
              </span>
              <span className="section-picker-item-name">{d.name}</span>
            </div>
            {inDept.map((p) => (
              <button
                key={p.id}
                type="button"
                className={`section-picker-item${value === p.id ? ' is-selected' : ''}`}
                style={{ '--sp-depth': d.depth + 1 }}
                onClick={() => { onChange(p.id); setOpen(false); }}
              >
                <span className="section-picker-item-indent" />
                <span className="section-picker-item-icon section-picker-item-icon--role">
                  <Icon name="user" size={14} />
                </span>
                <span className="section-picker-item-label">
                  <span className="section-picker-item-name">{p.name}</span>
                  {p.role && <span className="section-picker-item-meta">{p.role}</span>}
                </span>
                {value === p.id && <Icon name="check" size={14} className="section-picker-item-check" />}
              </button>
            ))}
          </React.Fragment>
        );
      })}
      {people.filter((p) => !p.departmentId).map((p) => (
        <button
          key={p.id}
          type="button"
          className={`section-picker-item${value === p.id ? ' is-selected' : ''}`}
          style={{ '--sp-depth': 0 }}
          onClick={() => { onChange(p.id); setOpen(false); }}
        >
          <span className="section-picker-item-indent" />
          <span className="section-picker-item-icon section-picker-item-icon--head">
            <Icon name="user" size={14} />
          </span>
          <span className="section-picker-item-label">
            <span className="section-picker-item-name">{p.name}</span>
            {p.role && <span className="section-picker-item-meta">{p.role}</span>}
          </span>
          {value === p.id && <Icon name="check" size={14} className="section-picker-item-check" />}
        </button>
      ))}
    </PickerShell>
  );
};

const PersonForm = ({ initial, onSave, onCancel, saving }) => {
  const defaultRole = (window.WORKSPACE_ROLES || []).find((r) => r.slug === 'viewer');
  const lockManager = Boolean(initial?.lockManagerId);
  const [form, setForm] = React.useState(() => ({
    name: initial?.name || '',
    email: initial?.email || '',
    phone: initial?.phone || '',
    role: initial?.role || '',
    departmentId: initial?.departmentId || '',
    managerId: initial?.managerId || '',
    workspaceRoleId: initial?.workspaceRoleId || defaultRole?.id || '',
    av: initial?.av || 'av-1',
    status: initial?.status || 'offline',
    password: '',
    generatePassword: !initial?.id,
  }));
  const [generatedPassword, setGeneratedPassword] = React.useState('');
  const [error, setError] = React.useState('');
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const roles = window.WORKSPACE_ROLES || [];
  const manager = window.findPerson(form.managerId);
  const department = window.findDepartment(form.departmentId);

  const pickDepartment = (departmentId) => {
    const suggested = !form.managerId && !lockManager
      ? (window.getSuggestedManagerForDept?.(departmentId) || '')
      : form.managerId;
    setForm((f) => ({
      ...f,
      departmentId,
      managerId: lockManager ? f.managerId : (suggested || f.managerId),
    }));
  };

  return (
    <form
      className="settings-form"
      onSubmit={async (e) => {
        e.preventDefault();
        setError('');
        if (!form.name?.trim()) {
          setError('Введите имя');
          return;
        }
        if (!form.departmentId) {
          setError('Выберите отдел');
          return;
        }
        if (!form.role?.trim()) {
          setError('Укажите должность (название роли)');
          return;
        }
        if (!form.workspaceRoleId) {
          setError('Выберите роль доступа');
          return;
        }
        if (!initial?.id && !form.generatePassword && (!form.password || form.password.length < 6)) {
          setError('Задайте пароль (мин. 6 символов) или включите генерацию');
          return;
        }
        if (!initial?.id && !form.email?.trim()) {
          setError('Укажите e-mail для входа');
          return;
        }
        try {
          const saved = await onSave({ ...initial, ...form, role: form.role.trim() });
          if (saved?.generatedPassword) setGeneratedPassword(saved.generatedPassword);
          else if (!initial?.id) onCancel?.();
        } catch (err) {
          setError(err.message || 'Не удалось сохранить');
        }
      }}
    >
      <label className="settings-field">
        <span>Имя и фамилия *</span>
        <input value={form.name} onChange={(e) => set('name', e.target.value)} required />
      </label>
      <div className="settings-form-row">
        <label className="settings-field">
          <span>E-mail *</span>
          <input type="email" value={form.email} onChange={(e) => set('email', e.target.value)} required />
        </label>
        <label className="settings-field">
          <span>Телефон</span>
          <input value={form.phone} onChange={(e) => set('phone', e.target.value)} />
        </label>
      </div>
      {!initial?.id ? (
        <div className="settings-field">
          <span>Пароль для входа *</span>
          <label className="settings-perm-row">
            <input
              type="checkbox"
              checked={form.generatePassword}
              onChange={(e) => set('generatePassword', e.target.checked)}
            />
            <span><strong>Сгенерировать пароль</strong><span className="text-xs text-3">Случайный надёжный пароль</span></span>
          </label>
          {!form.generatePassword && (
            <div className="login-pass-field">
              <input
                type="text"
                value={form.password}
                onChange={(e) => set('password', e.target.value)}
                placeholder="Минимум 6 символов"
                autoComplete="new-password"
              />
            </div>
          )}
          {generatedPassword && (
            <div className="login-generated">
              Пароль сотрудника: <strong>{generatedPassword}</strong>
              <div className="text-xs text-3" style={{ marginTop: 6 }}>Сохраните и передайте сотруднику — повторно показать нельзя.</div>
            </div>
          )}
        </div>
      ) : (
        <div className="settings-field">
          <span>Пароль</span>
          <button
            type="button"
            className="btn btn-ghost btn-sm"
            onClick={async () => {
              try {
                const res = await window.KB.resetPersonPassword(initial.id, { generate: true });
                setGeneratedPassword(res.password || '');
              } catch (err) {
                setError(err.message || 'Не удалось сбросить пароль');
              }
            }}
          >
            Сгенерировать новый пароль
          </button>
          {generatedPassword && (
            <div className="login-generated">Новый пароль: <strong>{generatedPassword}</strong></div>
          )}
          {initial.hasPassword && !generatedPassword && (
            <span className="text-xs text-3">Пароль задан — вход по e-mail возможен</span>
          )}
        </div>
      )}
      <label className="settings-field">
        <span>Отдел *</span>
        <DepartmentTreePicker
          value={form.departmentId}
          onChange={pickDepartment}
          placeholder="— выберите отдел —"
        />
        <span className="text-xs text-3">
          Сначала создайте дерево отделов в настройках → Структура
        </span>
      </label>
      <label className="settings-field">
        <span>Должность (название роли) *</span>
        <input
          value={form.role}
          onChange={(e) => set('role', e.target.value)}
          placeholder="Владелец, HR-менеджер, Разработчик…"
          required
        />
      </label>
      {lockManager ? (
        <div className="settings-field">
          <span>Кому подчиняется</span>
          <div className="settings-readonly-field">{manager?.name || '—'}</div>
        </div>
      ) : (
        <label className="settings-field">
          <span>Кому подчиняется</span>
          <ManagerPersonPicker
            value={form.managerId}
            onChange={(id) => set('managerId', id)}
            excludeId={initial?.id}
          />
          <span className="text-xs text-3">
            Пусто = владелец / верхний уровень. Для руководителя IT выберите владельца; для сотрудника IT — руководителя IT.
          </span>
        </label>
      )}
      <label className="settings-field">
        <span>Роль доступа *</span>
        <RoleListPicker
          value={form.workspaceRoleId}
          onChange={(id) => set('workspaceRoleId', id)}
          roles={roles}
          placeholder="— выберите роль —"
        />
      </label>
      {department && (
        <div className="settings-info-box text-xs">
          На схеме: <strong>{manager?.name || 'верхний уровень'}</strong>
          {' → '}
          <strong>{form.role || '—'}</strong>
          {' · '}
          {department.name}
        </div>
      )}
      <label className="settings-field">
        <span>Аватар</span>
        <div className="settings-avatar-pick">
          {AVATARS.map((av) => (
            <button
              key={av}
              type="button"
              className={`avatar avatar-sm ${av}${form.av === av ? ' is-selected' : ''}`}
              onClick={() => set('av', av)}
            />
          ))}
        </div>
      </label>
      {error && <p className="settings-form-error">{error}</p>}
      <div className="settings-form-actions">
        <button type="button" className="btn btn-ghost" onClick={onCancel}>Отмена</button>
        <button type="submit" className="btn btn-primary" disabled={saving}>
          {saving ? 'Сохранение…' : 'Сохранить'}
        </button>
      </div>
    </form>
  );
};

const DepartmentForm = ({ initial, onSave, onCancel, saving }) => {
  const [form, setForm] = React.useState({
    name: initial?.name || '',
    parentId: initial?.parentId || '',
    color: initial?.color || 'dept-blue',
    sortOrder: initial?.sortOrder ?? 0,
  });
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  return (
    <form
      className="settings-form"
      onSubmit={async (e) => {
        e.preventDefault();
        await onSave({ ...initial, ...form });
      }}
    >
      <label className="settings-field">
        <span>Название отдела *</span>
        <input value={form.name} onChange={(e) => set('name', e.target.value)} required />
      </label>
      <label className="settings-field">
        <span>Родительский отдел</span>
        <DepartmentTreePicker
          value={form.parentId}
          onChange={(id) => set('parentId', id)}
          placeholder="— корневой (уровень компании) —"
          excludeId={initial?.id}
        />
        <span className="text-xs text-3">
          Дерево отделов: Компания → IT → Backend. Корневой отдел = на одном уровне с компанией.
        </span>
      </label>
      <label className="settings-field">
        <span>Цвет</span>
        <div className="settings-color-pick">
          {DEPT_COLORS.map((c) => (
            <button
              key={c}
              type="button"
              className={`settings-color-swatch ${c}${form.color === c ? ' is-selected' : ''}`}
              onClick={() => set('color', c)}
            />
          ))}
        </div>
      </label>
      <div className="settings-form-actions">
        <button type="button" className="btn btn-ghost" onClick={onCancel}>Отмена</button>
        <button type="submit" className="btn btn-primary" disabled={saving}>
          {saving ? 'Сохранение…' : 'Сохранить'}
        </button>
      </div>
    </form>
  );
};

const PositionForm = ({ initial, onSave, onCancel, saving }) => {
  const defaultRole = (window.WORKSPACE_ROLES || []).find((r) => r.slug === 'viewer');
  const lockParent = Boolean(initial?.lockParent);
  const parentPreset = initial?.parentPositionId
    ? window.findPosition(initial.parentPositionId)
    : null;

  const [form, setForm] = React.useState({
    name: initial?.name || '',
    departmentId: initial?.departmentId || parentPreset?.departmentId || '',
    parentPositionId: initial?.parentPositionId || '',
    workspaceRoleId: initial?.workspaceRoleId || defaultRole?.id || '',
    color: initial?.color || parentPreset?.color || 'dept-blue',
  });
  const [error, setError] = React.useState('');

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const departments = window.DEPARTMENTS || [];
  const roles = window.WORKSPACE_ROLES || [];
  const parentPosition = window.findPosition(form.parentPositionId);
  const department = departments.find((d) => d.id === form.departmentId);

  const pickParentPosition = (parentPositionId) => {
    const parent = parentPositionId ? window.findPosition(parentPositionId) : null;
    const dept = parent ? departments.find((d) => d.id === parent.departmentId) : null;
    setForm((f) => ({
      ...f,
      parentPositionId,
      departmentId: parent?.departmentId ?? f.departmentId,
      color: dept?.color || parent?.color || f.color,
    }));
  };

  const pickDepartment = (departmentId) => {
    const dept = departments.find((d) => d.id === departmentId);
    setForm((f) => ({
      ...f,
      departmentId,
      color: dept?.color || f.color,
    }));
  };

  const deptHead = form.departmentId ? window.getDepartmentHeadPosition?.(form.departmentId) : null;

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError('');
    if (!form.name?.trim()) {
      setError('Введите название должности');
      return;
    }
    if (!form.workspaceRoleId) {
      setError('Выберите роль доступа');
      return;
    }
    const isDeptHead = !form.parentPositionId && form.departmentId;
    if (!initial?.id && !initial?.allowRoot && !lockParent && !form.parentPositionId && !isDeptHead) {
      setError('Выберите должность-начальника — или отдел, если создаёте руководителя отдела');
      return;
    }
    try {
      await onSave({
        ...initial,
        ...form,
        name: form.name.trim(),
        description: '',
        lockParent: undefined,
      });
    } catch (err) {
      setError(err.message || 'Не удалось сохранить');
    }
  };

  return (
    <form className="settings-form" onSubmit={handleSubmit}>
      <label className="settings-field">
        <span>Название должности *</span>
        <input
          value={form.name}
          onChange={(e) => set('name', e.target.value)}
          placeholder="Например: CTO, Head of Marketing"
          required
        />
        <span className="text-xs text-3">
          Сохранится в настройках → Должности и появится в выборе при назначении сотрудников
        </span>
      </label>

      {lockParent && parentPreset ? (
        <div className="settings-info-box text-sm">
          <strong>Место на схеме:</strong> подчиняется «{parentPreset.name}»
          {parentPreset.departmentName ? ` · ${parentPreset.departmentName}` : ''}
        </div>
      ) : (
        <label className="settings-field">
          <span>Кому подчиняется на схеме</span>
          <ParentPositionTreePicker
            value={form.parentPositionId}
            onChange={pickParentPosition}
            excludeId={initial?.id}
          />
          <span className="text-xs text-3">
            <strong>Кто выше на оргсхеме</strong> — выбираете другую должность (не отдел).
            Папки CRM / E-com в списке только группируют должности для поиска.
            Для обычной роли укажите своего непосредственного начальника
            {deptHead ? ` («${deptHead.name}» в этом отделе)` : ''}.
          </span>
        </label>
      )}

      <label className="settings-field">
        <span>Отдел</span>
        {lockParent || parentPosition ? (
          <div className="settings-readonly-field">
            {department?.name || parentPosition?.departmentName || '—'}
          </div>
        ) : (
          <DepartmentTreePicker
            value={form.departmentId}
            onChange={pickDepartment}
            placeholder="— не выбран —"
          />
        )}
        <span className="text-xs text-3">
          {lockParent || parentPosition
            ? 'Берётся из должности начальника'
            : 'Справочник подразделений: цвет карточки и группировка. Для руководителя отдела выберите отдел и «верхний уровень» выше'}
        </span>
      </label>

      <label className="settings-field">
        <span>Роль доступа *</span>
        <RoleListPicker
          value={form.workspaceRoleId}
          onChange={(id) => set('workspaceRoleId', id)}
          roles={roles}
          placeholder="— выберите роль —"
        />
      </label>

      {!lockParent && (
        <label className="settings-field">
          <span>Цвет карточки</span>
          <div className="settings-color-pick">
            {DEPT_COLORS.map((c) => (
              <button
                key={c}
                type="button"
                className={`settings-color-swatch ${c}${form.color === c ? ' is-selected' : ''}`}
                onClick={() => set('color', c)}
              />
            ))}
          </div>
        </label>
      )}

      <div className="settings-info-box text-xs">
        Права назначаются должности. Все сотрудники на этой должности получают выбранную роль.
      </div>

      {error && <p className="settings-form-error">{error}</p>}

      <div className="settings-form-actions">
        <button type="button" className="btn btn-ghost" onClick={onCancel} disabled={saving}>Отмена</button>
        <button type="submit" className="btn btn-primary" disabled={saving}>
          {saving ? 'Сохранение…' : 'Сохранить'}
        </button>
      </div>
    </form>
  );
};

window.WorkspaceForms = {
  SettingsModal,
  PersonForm,
  DepartmentForm,
  PositionForm,
  DEPT_COLORS,
  AVATARS,
};
