/* =====================================================================
 * Gestion des utilisateurs & droits d'accès (réservé aux administrateurs).
 * ===================================================================== */

function UserAvatar({ user, size = 'md' }) {
  const role = roleOf(user.role);
  const colors = { red: 'bg-red-600', blue: 'bg-blue-600', amber: 'bg-amber-500' };
  const sizes = { sm: 'h-8 w-8 text-xs', md: 'h-10 w-10 text-sm' };
  return (
    <span className={cx('flex shrink-0 items-center justify-center rounded-full font-bold text-white', colors[role.tone], sizes[size])}>{initials(user)}</span>
  );
}

function UserForm({ user, onClose, onSave }) {
  const { users } = useApp();
  const [draft, setDraft] = useState(user);
  const [password, setPassword] = useState('');
  const set = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
  const isNew = !user.nom;
  const validEmail = !draft.email || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(draft.email);
  const identifiant = (draft.identifiant || '').trim().toLowerCase();
  const identifiantError = !identifiant
    ? 'Identifiant obligatoire'
    : !/^[a-z0-9._-]+$/.test(identifiant)
      ? 'Lettres sans accent, chiffres, « . », « _ » ou « - » uniquement'
      : users.some((u) => u.id !== draft.id && (u.identifiant || '').toLowerCase() === identifiant)
        ? 'Identifiant déjà utilisé'
        : null;
  const pwdError = password ? passwordError(password) : null;
  const valid = draft.nom.trim() && draft.prenom.trim() && validEmail && !identifiantError && !pwdError;

  const submit = () => onSave({ ...draft, identifiant, password: password || undefined });

  const changeRole = (role) => setDraft((d) => ({ ...d, role, access: { ...roleOf(role).defaults } }));

  return (
    <Modal
      open
      size="md"
      icon={UserCog}
      title={isNew ? 'Nouvel utilisateur' : `Modifier ${user.prenom} ${user.nom}`}
      onClose={onClose}
      footer={
        <Fragment>
          <Button variant="secondary" onClick={onClose}>
            Annuler
          </Button>
          <Button icon={Save} disabled={!valid} onClick={submit}>
            Enregistrer
          </Button>
        </Fragment>
      }
    >
      <div className="grid gap-4 sm:grid-cols-2">
        <Field label="Nom">
          <TextInput
            value={draft.nom}
            onChange={(v) => setDraft((d) => ({ ...d, nom: v, identifiant: isNew && !user.identifiant ? defaultIdentifiant({ ...d, nom: v }, users) : d.identifiant }))}
            autoFocus
          />
        </Field>
        <Field label="Prénom">
          <TextInput
            value={draft.prenom}
            onChange={(v) => setDraft((d) => ({ ...d, prenom: v, identifiant: isNew && !user.identifiant ? defaultIdentifiant({ ...d, prenom: v }, users) : d.identifiant }))}
          />
        </Field>
        <Field label="Identifiant de connexion" hint={identifiantError || undefined}>
          <TextInput value={draft.identifiant || ''} onChange={(v) => set('identifiant', v)} className={identifiantError ? 'border-red-400' : ''} />
        </Field>
        <Field
          label={isNew ? 'Mot de passe initial' : 'Nouveau mot de passe'}
          hint={
            pwdError ||
            (isNew ? "Sans mot de passe, le compte ne peut pas se connecter. L'utilisateur devra le changer à sa première connexion." : 'Laisser vide pour ne pas le modifier.')
          }
        >
          <PasswordInput value={password} onChange={setPassword} autoComplete="new-password" />
        </Field>
        <Field label="Grade">
          <SelectInput value={draft.grade} onChange={(v) => set('grade', v)} options={GRADES} />
        </Field>
        <Field label="Email" hint={!validEmail ? 'Adresse email invalide' : undefined}>
          <TextInput type="email" value={draft.email} onChange={(v) => set('email', v)} className={!validEmail ? 'border-red-400' : ''} />
        </Field>
        <Field label="Rôle" className="sm:col-span-2" hint="Le changement de rôle applique les accès par défaut, modifiables ci-dessous.">
          <Segmented options={ROLES.map((r) => ({ value: r.value, label: r.label, tone: r.tone }))} value={draft.role} onChange={changeRole} allowEmpty={false} />
        </Field>
        <Field label="Accès aux modules" className="sm:col-span-2">
          {draft.role === 'admin' ? (
            <p className="rounded-lg bg-red-50 p-3 text-sm text-red-700">Un administrateur dispose d'un accès complet à tous les modules.</p>
          ) : (
            <div className="flex flex-wrap gap-6 rounded-lg bg-slate-50 p-3">
              <Switch label="Bilans SAP" checked={draft.access.sap} onChange={(v) => set('access', { ...draft.access, sap: v })} />
              <Switch label="Tenues JSP" checked={draft.access.jsp} onChange={(v) => set('access', { ...draft.access, jsp: v })} />
            </div>
          )}
        </Field>
        <Field label="Compte" className="sm:col-span-2">
          <Switch label={draft.actif ? 'Compte actif' : 'Compte désactivé'} checked={draft.actif} onChange={(v) => set('actif', v)} />
        </Field>
      </div>
    </Modal>
  );
}

function DataManagement() {
  const { settings, setSettings, notify, exportServerData, importServerData, legacyAvailable, importLegacy } = useApp();
  const fileRef = useRef(null);
  const [busy, setBusy] = useState(false);

  const guard = async (fn) => {
    setBusy(true);
    try {
      await fn();
    } catch (err) {
      notify(err.message || 'Opération impossible', 'red');
    } finally {
      setBusy(false);
    }
  };

  const doExport = () =>
    guard(async () => {
      const data = await exportServerData();
      downloadFile(`sap-manager-sauvegarde-${new Date().toISOString().slice(0, 10)}.json`, JSON.stringify(data, null, 2), 'application/json');
      notify('Sauvegarde exportée');
    });

  const doImport = (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = '';
    if (!file) return;
    if (!window.confirm('Remplacer les bilans, les JSP et le stock du serveur par le contenu de ce fichier ?')) return;
    const reader = new FileReader();
    reader.onload = () =>
      guard(async () => {
        let payload;
        try {
          payload = JSON.parse(reader.result);
        } catch (err) {
          throw new Error('Fichier illisible (JSON attendu).');
        }
        await importServerData(payload);
        notify('Sauvegarde restaurée');
      });
    reader.readAsText(file);
  };

  const doLegacy = () =>
    guard(async () => {
      const counts = await importLegacy();
      notify(counts ? `Transfert terminé : ${counts.bilans} bilan(s), ${counts.jsp} JSP, ${counts.users} compte(s) ajoutés` : 'Aucune donnée à transférer');
    });

  return (
    <div className="grid gap-5 lg:grid-cols-2">
      <Card title="Paramètres du centre" icon={Settings}>
        <div className="grid gap-4 sm:grid-cols-2">
          <Field label="Nom du centre de secours">
            <TextInput value={settings.centre} onChange={(v) => setSettings({ ...settings, centre: v })} />
          </Field>
          <Field label="Département / SDIS">
            <TextInput value={settings.departement} onChange={(v) => setSettings({ ...settings, departement: v })} />
          </Field>
        </div>
        <p className="mt-3 text-xs text-slate-400">Ces informations apparaissent en en-tête des fiches imprimées.</p>
      </Card>

      <Card title="Sauvegardes" icon={Package}>
        <p className="mb-4 text-sm text-slate-600">
          Les comptes et les données sont enregistrés sur le serveur. Exportez régulièrement une sauvegarde (elle contient des données
          médicales : conservez-la en lieu sûr).
        </p>
        <div className="flex flex-wrap gap-2">
          <Button variant="secondary" icon={Download} disabled={busy} onClick={doExport}>
            Exporter
          </Button>
          <Button variant="secondary" icon={Upload} disabled={busy} onClick={() => fileRef.current && fileRef.current.click()}>
            Restaurer
          </Button>
          <input ref={fileRef} type="file" accept="application/json,.json" className="hidden" onChange={doImport} />
        </div>
        {legacyAvailable && (
          <div className="mt-4 rounded-lg bg-amber-50 p-3 text-sm text-amber-800">
            <p className="mb-2">Ce navigateur contient encore des données de l'ancienne version (stockage local).</p>
            <Button size="sm" icon={Upload} disabled={busy} onClick={doLegacy}>
              Les transférer sur le serveur
            </Button>
          </div>
        )}
      </Card>
    </div>
  );
}

function UsersModule() {
  const { users, currentUser, upsertUser, deleteUser, refreshUsers, notify } = useApp();
  const [editing, setEditing] = useState(null);
  const [passwordFor, setPasswordFor] = useState(null);
  const [query, setQuery] = useState('');
  const [recreating, setRecreating] = useState(false);

  const recreateAccounts = async () => {
    if (!window.confirm('Recréer les comptes Noé Beaugrand et Bastien Valentin, et retirer tous les autres comptes ?')) return;
    setRecreating(true);
    try {
      await apiRequest('users/recreate', { method: 'POST' });
      await refreshUsers();
      notify('Comptes recréés');
    } catch (err) {
      notify(err.message || 'Recréation impossible', 'red');
    } finally {
      setRecreating(false);
    }
  };

  const admins = users.filter((u) => u.role === 'admin' && u.actif);
  const isLastAdmin = (u) => u.role === 'admin' && u.actif && admins.length <= 1;

  const visible = users.filter((u) => {
    const q = query.trim().toLowerCase();
    return !q || `${u.nom} ${u.prenom} ${u.email} ${u.grade}`.toLowerCase().includes(q);
  });

  const fail = (err) => notify(err.message || 'Opération impossible', 'red');

  const save = async (u) => {
    const before = users.find((x) => x.id === u.id);
    if (before && isLastAdmin(before) && (u.role !== 'admin' || !u.actif)) {
      notify('Impossible : il doit rester au moins un administrateur actif', 'red');
      return;
    }
    try {
      await upsertUser(u);
      setEditing(null);
      notify('Utilisateur enregistré');
    } catch (err) {
      fail(err);
    }
  };

  const toggleAccess = (u, key, value) => upsertUser({ ...u, access: { ...u.access, [key]: value } }).catch(fail);

  const toggleActif = (u, value) => {
    if (!value && (u.id === currentUser.id || isLastAdmin(u))) {
      notify(u.id === currentUser.id ? 'Vous ne pouvez pas désactiver votre propre compte' : 'Dernier administrateur actif', 'red');
      return;
    }
    upsertUser({ ...u, actif: value }).catch(fail);
  };

  const remove = async (u) => {
    if (u.id === currentUser.id) return notify('Vous ne pouvez pas supprimer votre propre compte', 'red');
    if (isLastAdmin(u)) return notify('Impossible de supprimer le dernier administrateur', 'red');
    if (!window.confirm(`Supprimer le compte de ${u.prenom} ${u.nom} ?`)) return;
    try {
      await deleteUser(u.id);
      notify('Utilisateur supprimé', 'red');
    } catch (err) {
      fail(err);
    }
  };

  const userIdentity = (u) => (
    <div className="flex items-center gap-3">
      <UserAvatar user={u} />
      <div className="min-w-0">
        <p className="font-semibold text-slate-800">
          {u.prenom} {u.nom.toUpperCase()} {u.id === currentUser.id && <Badge tone="blue">Vous</Badge>}
        </p>
        <p className="break-all text-xs text-slate-500">
          <span className="font-mono">{u.identifiant || '—'}</span>
          {u.email ? ` · ${u.email}` : ''}
        </p>
      </div>
    </div>
  );

  const passwordBadge = (u) => (
    <button type="button" onClick={() => setPasswordFor(u)} title="Définir le mot de passe">
      {u.hasPassword ? (
        <Badge tone={u.mustChangePassword ? 'amber' : 'emerald'}>
          <LockIcon className="h-3 w-3" /> {u.mustChangePassword ? 'Provisoire' : 'Défini'}
        </Badge>
      ) : (
        <Badge tone="red">Aucun mot de passe</Badge>
      )}
    </button>
  );

  const userActions = (u) => (
    <Fragment>
      <IconButton icon={LockIcon} title="Définir le mot de passe" onClick={() => setPasswordFor(u)} />
      <IconButton icon={Pencil} tone="blue" title="Modifier" onClick={() => setEditing(u)} />
      <IconButton icon={Trash2} tone="red" title="Supprimer" onClick={() => remove(u)} />
    </Fragment>
  );

  const newUser = () =>
    setEditing({ id: uid(), identifiant: '', nom: '', prenom: '', grade: '', email: '', role: 'chef_agres', access: { ...roleOf('chef_agres').defaults }, actif: true });

  return (
    <div className="space-y-6">
      <PageHeader
        title="Gestion des utilisateurs & accès"
        subtitle="Comptes, rôles et autorisations par module"
        icon={ShieldCheck}
        actions={
          <Fragment>
            <Button variant="secondary" icon={RotateCcw} disabled={recreating} onClick={recreateAccounts}>
              Recréer les comptes
            </Button>
            <Button icon={UserPlus} onClick={newUser}>
              Nouvel utilisateur
            </Button>
          </Fragment>
        }
      />

      <div className="hidden gap-3 sm:grid sm:grid-cols-3">
        {ROLES.map((r) => (
          <div key={r.value} className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
            <div className="flex items-center justify-between">
              <Badge tone={r.tone}>{r.label}</Badge>
              <span className="text-2xl font-bold">{users.filter((u) => u.role === r.value).length}</span>
            </div>
            <p className="mt-2 text-xs text-slate-500">
              Par défaut : {r.value === 'admin' ? 'tous les modules + gestion des accès' : [r.defaults.sap && 'Bilans SAP', r.defaults.jsp && 'Tenues JSP'].filter(Boolean).join(', ')}
            </p>
          </div>
        ))}
      </div>

      <Card
        title="Comptes"
        icon={Users}
        bodyClassName="p-0"
        actions={<SearchInput className="w-full sm:w-64" value={query} onChange={setQuery} placeholder="Rechercher…" />}
      >
        <ul className="divide-y divide-slate-100 md:hidden">
          {visible.map((u) => {
            const role = roleOf(u.role);
            const admin = u.role === 'admin';
            return (
              <li key={u.id} className={cx('space-y-3 p-4', !u.actif && 'bg-slate-50 opacity-60')}>
                {userIdentity(u)}
                <div className="flex flex-wrap items-center gap-2">
                  <Badge tone={role.tone}>{role.label}</Badge>
                  {passwordBadge(u)}
                  {u.grade && <span className="text-xs text-slate-500">{u.grade}</span>}
                </div>
                <div className="flex flex-wrap gap-x-5 gap-y-2 rounded-lg bg-slate-50 p-3">
                  <Switch label="SAP" checked={admin || u.access.sap} disabled={admin} onChange={(v) => toggleAccess(u, 'sap', v)} />
                  <Switch label="JSP" checked={admin || u.access.jsp} disabled={admin} onChange={(v) => toggleAccess(u, 'jsp', v)} />
                  <Switch label="Actif" checked={u.actif} onChange={(v) => toggleActif(u, v)} />
                </div>
                <div className="flex justify-end gap-1">{userActions(u)}</div>
              </li>
            );
          })}
        </ul>
        <div className="scrollbar-thin hidden overflow-x-auto md:block">
          <table className="w-full min-w-[820px] text-sm">
            <thead className="bg-slate-50 text-left text-xs uppercase tracking-wide text-slate-500">
              <tr>
                <th className="px-4 py-3">Utilisateur</th>
                <th className="px-4 py-3">Grade</th>
                <th className="px-4 py-3">Mot de passe</th>
                <th className="px-4 py-3">Rôle</th>
                <th className="px-4 py-3 text-center">Bilans SAP</th>
                <th className="px-4 py-3 text-center">Tenues JSP</th>
                <th className="px-4 py-3 text-center">Actif</th>
                <th className="px-4 py-3 text-right">Actions</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-100">
              {visible.map((u) => {
                const role = roleOf(u.role);
                const admin = u.role === 'admin';
                return (
                  <tr key={u.id} className={cx(!u.actif && 'bg-slate-50 opacity-60')}>
                    <td className="px-4 py-3">{userIdentity(u)}</td>
                    <td className="px-4 py-3 text-slate-600">{u.grade || '—'}</td>
                    <td className="px-4 py-3">{passwordBadge(u)}</td>
                    <td className="px-4 py-3">
                      <Badge tone={role.tone}>{role.label}</Badge>
                    </td>
                    <td className="px-4 py-3 text-center">
                      <Switch checked={admin || u.access.sap} disabled={admin} onChange={(v) => toggleAccess(u, 'sap', v)} />
                    </td>
                    <td className="px-4 py-3 text-center">
                      <Switch checked={admin || u.access.jsp} disabled={admin} onChange={(v) => toggleAccess(u, 'jsp', v)} />
                    </td>
                    <td className="px-4 py-3 text-center">
                      <Switch checked={u.actif} onChange={(v) => toggleActif(u, v)} />
                    </td>
                    <td className="px-4 py-3">
                      <div className="flex justify-end gap-1">{userActions(u)}</div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>

      <DataManagement />

      {editing && <UserForm key={editing.id} user={editing} onClose={() => setEditing(null)} onSave={save} />}
      {passwordFor && <AdminPasswordModal user={passwordFor} onClose={() => setPasswordFor(null)} />}
    </div>
  );
}
