import { api } from '@/api/client';
import { useAuth } from '@/auth/AuthProvider';
import type { ManagedUser, Role, RoleOption } from '@/auth/types';
import { formatDateTime } from '@/lib/format';
import { useCallback, useEffect, useState, type FormEvent } from 'react';

type UsersPayload = { users: ManagedUser[]; roles: RoleOption[] };
type AuditEntry = { actor: string; action: string; subject: string; detail: Record<string, unknown>; createdAt: string };

const emptyDraft = { username: '', displayName: '', role: 'buero' as Role, password: '' };

/**
 * Benutzerverwaltung.
 *
 * Nur fuer die Rolle Administration sichtbar. Das Backend setzt dieselben Regeln
 * noch einmal durch -- diese Ansicht macht sie nur sichtbar, sie ersetzt sie nicht.
 */
export function UsersView() {
    const { user: currentUser } = useAuth();
    const [users, setUsers] = useState<ManagedUser[]>([]);
    const [roles, setRoles] = useState<RoleOption[]>([]);
    const [audit, setAudit] = useState<AuditEntry[]>([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState('');
    const [notice, setNotice] = useState('');
    const [busyId, setBusyId] = useState<string | null>(null);

    const [creating, setCreating] = useState(false);
    const [draft, setDraft] = useState(emptyDraft);
    const [editing, setEditing] = useState<ManagedUser | null>(null);
    const [editDraft, setEditDraft] = useState({ username: '', displayName: '', role: 'buero' as Role, password: '' });
    const [deleteConfirming, setDeleteConfirming] = useState<string | null>(null);

    const refresh = useCallback(async () => {
        setLoading(true);
        setError('');

        try {
            const data = await api.get<UsersPayload>('/api/users');
            setUsers(data.users);
            setRoles(data.roles);
        } catch (problem) {
            setError(problem instanceof Error ? problem.message : 'Die Benutzer konnten nicht geladen werden.');
        } finally {
            setLoading(false);
        }
    }, []);

    const refreshAudit = useCallback(async () => {
        try {
            const data = await api.get<{ entries: AuditEntry[] }>('/api/users/audit');
            setAudit(data.entries);
        } catch {
            // Das Protokoll ist eine Beigabe. Faellt es aus, bleibt die Verwaltung nutzbar.
        }
    }, []);

    useEffect(() => {
        void refresh();
        void refreshAudit();
    }, [refresh, refreshAudit]);

    const run = async (id: string | null, action: () => Promise<string>) => {
        setBusyId(id ?? 'form');
        setError('');
        setNotice('');

        try {
            setNotice(await action());
            await refresh();
            await refreshAudit();
        } catch (problem) {
            setError(problem instanceof Error ? problem.message : 'Die Aktion ist fehlgeschlagen.');
        } finally {
            setBusyId(null);
        }
    };

    const create = (event: FormEvent) => {
        event.preventDefault();

        void run(null, async () => {
            await api.post('/api/users', draft);
            setDraft(emptyDraft);
            setCreating(false);

            return `Benutzer „${draft.displayName}“ wurde angelegt.`;
        });
    };

    const saveEdit = (event: FormEvent) => {
        event.preventDefault();
        if (!editing) return;

        void run(editing.id, async () => {
            const changes: Record<string, unknown> = {};

            if (editDraft.displayName !== editing.displayName) changes.displayName = editDraft.displayName;
            if (editDraft.username !== editing.username) changes.username = editDraft.username;
            if (editDraft.role !== editing.role) changes.role = editDraft.role;
            if (editDraft.password !== '') changes.password = editDraft.password;

            if (Object.keys(changes).length === 0) {
                setEditing(null);
                return 'Es wurde nichts geändert.';
            }

            const result = await api.patch<{ endedSessions: number }>(`/api/users/${editing.id}`, changes);
            setEditing(null);

            return result.endedSessions > 0
                ? `Gespeichert. ${result.endedSessions} offene Sitzung(en) wurden beendet.`
                : 'Gespeichert.';
        });
    };

    const toggleActive = (user: ManagedUser) =>
        void run(user.id, async () => {
            await api.patch(`/api/users/${user.id}`, { isActive: !user.isActive });

            return user.isActive ? `„${user.displayName}“ ist jetzt deaktiviert.` : `„${user.displayName}“ ist wieder aktiv.`;
        });

    const remove = (user: ManagedUser) =>
        void run(user.id, async () => {
            await api.delete(`/api/users/${user.id}`);
            setDeleteConfirming(null);

            return `Benutzer „${user.displayName}“ wurde gelöscht.`;
        });

    const startEdit = (user: ManagedUser) => {
        setEditing(user);
        setEditDraft({ username: user.username, displayName: user.displayName, role: user.role, password: '' });
        setCreating(false);
        setNotice('');
        setError('');
    };

    const activeAdmins = users.filter((user) => user.role === 'admin' && user.isActive).length;

    return (
        <section className="tickets-page users-page">
            <div className="tickets-heading">
                <div>
                    <p className="home-kicker">Verwaltung</p>
                    <h2>Benutzer</h2>
                    <p>
                        Konten, Rollen und Rechte für EK-DOS. Jede Änderung an Rolle, Passwort oder Status beendet die offenen
                        Sitzungen des betroffenen Kontos sofort.
                    </p>
                </div>
                <div className="tickets-actions">
                    <span>{users.length} Konten · {activeAdmins} aktive Administration</span>
                    <button
                        onClick={() => {
                            setCreating((open) => !open);
                            setEditing(null);
                        }}
                    >
                        {creating ? 'Abbrechen' : 'Benutzer anlegen'}
                    </button>
                </div>
            </div>

            {error && <p className="tickets-error">{error}</p>}
            {notice && <p className="users-notice">{notice}</p>}

            {creating && (
                <form className="users-form" onSubmit={create}>
                    <h3>Neuer Benutzer</h3>
                    <div className="users-form-grid">
                        <label>
                            Benutzername
                            <input
                                value={draft.username}
                                onChange={(event) => setDraft({ ...draft, username: event.target.value })}
                                placeholder="z. B. svenja"
                                autoComplete="off"
                                required
                            />
                        </label>
                        <label>
                            Anzeigename
                            <input
                                value={draft.displayName}
                                onChange={(event) => setDraft({ ...draft, displayName: event.target.value })}
                                placeholder="z. B. Svenja"
                                required
                            />
                        </label>
                        <label>
                            Rolle
                            <select value={draft.role} onChange={(event) => setDraft({ ...draft, role: event.target.value as Role })}>
                                {roles.map((role) => (
                                    <option key={role.value} value={role.value}>
                                        {role.label}
                                    </option>
                                ))}
                            </select>
                        </label>
                        <label>
                            Passwort
                            <input
                                type="password"
                                value={draft.password}
                                onChange={(event) => setDraft({ ...draft, password: event.target.value })}
                                autoComplete="new-password"
                                minLength={12}
                                required
                            />
                            <small>Mindestens 12 Zeichen.</small>
                        </label>
                    </div>
                    <RolePermissions roles={roles} selected={draft.role} />
                    <button type="submit" disabled={busyId === 'form'}>
                        {busyId === 'form' ? 'Wird angelegt …' : 'Benutzer anlegen'}
                    </button>
                </form>
            )}

            {editing && (
                <form className="users-form" onSubmit={saveEdit}>
                    <h3>{editing.displayName} bearbeiten</h3>
                    <div className="users-form-grid">
                        <label>
                            Benutzername
                            <input
                                value={editDraft.username}
                                onChange={(event) => setEditDraft({ ...editDraft, username: event.target.value })}
                                autoComplete="off"
                                required
                            />
                        </label>
                        <label>
                            Anzeigename
                            <input
                                value={editDraft.displayName}
                                onChange={(event) => setEditDraft({ ...editDraft, displayName: event.target.value })}
                                required
                            />
                        </label>
                        <label>
                            Rolle
                            <select
                                value={editDraft.role}
                                onChange={(event) => setEditDraft({ ...editDraft, role: event.target.value as Role })}
                                disabled={editing.id === currentUser?.id}
                            >
                                {roles.map((role) => (
                                    <option key={role.value} value={role.value}>
                                        {role.label}
                                    </option>
                                ))}
                            </select>
                            {editing.id === currentUser?.id && <small>Die eigene Rolle kann nicht geändert werden.</small>}
                        </label>
                        <label>
                            Neues Passwort
                            <input
                                type="password"
                                value={editDraft.password}
                                onChange={(event) => setEditDraft({ ...editDraft, password: event.target.value })}
                                autoComplete="new-password"
                                placeholder="leer lassen, um es beizubehalten"
                            />
                        </label>
                    </div>
                    <RolePermissions roles={roles} selected={editDraft.role} />
                    <div className="users-form-actions">
                        <button type="submit" disabled={busyId === editing.id}>
                            {busyId === editing.id ? 'Wird gespeichert …' : 'Speichern'}
                        </button>
                        <button type="button" className="users-secondary" onClick={() => setEditing(null)}>
                            Abbrechen
                        </button>
                    </div>
                </form>
            )}

            <div className="tickets-table-wrap">
                <table className="tickets-table">
                    <thead>
                        <tr>
                            <th>Benutzer</th>
                            <th>Rolle</th>
                            <th>Status</th>
                            <th>Letzte Anmeldung</th>
                            <th>Aktionen</th>
                        </tr>
                    </thead>
                    <tbody>
                        {loading && users.length === 0 && (
                            <tr>
                                <td colSpan={5}>Benutzer werden geladen …</td>
                            </tr>
                        )}
                        {!loading && users.length === 0 && (
                            <tr>
                                <td colSpan={5}>Es ist noch kein Benutzer angelegt.</td>
                            </tr>
                        )}
                        {users.map((user) => (
                            <tr key={user.id}>
                                <td>
                                    <b>{user.displayName}</b>
                                    <small>{user.username}{user.id === currentUser?.id ? ' · das bist du' : ''}</small>
                                </td>
                                <td>
                                    <span className={`ticket-status users-role-${user.role}`}>{user.roleLabel}</span>
                                </td>
                                <td>
                                    <span className={user.isActive ? 'users-state-active' : 'users-state-inactive'}>
                                        {user.isActive ? 'aktiv' : 'deaktiviert'}
                                    </span>
                                </td>
                                <td>{user.lastLoginAt ? formatDateTime(user.lastLoginAt) : 'noch nie'}</td>
                                <td className="users-actions">
                                    <button onClick={() => startEdit(user)} disabled={busyId !== null}>
                                        Bearbeiten
                                    </button>
                                    <button
                                        onClick={() => toggleActive(user)}
                                        disabled={busyId !== null || user.id === currentUser?.id}
                                        title={user.id === currentUser?.id ? 'Das eigene Konto kann nicht deaktiviert werden.' : ''}
                                    >
                                        {user.isActive ? 'Deaktivieren' : 'Aktivieren'}
                                    </button>
                                    {deleteConfirming === user.id ? (
                                        <>
                                            <button className="users-danger" onClick={() => remove(user)} disabled={busyId !== null}>
                                                Wirklich löschen
                                            </button>
                                            <button onClick={() => setDeleteConfirming(null)}>Abbrechen</button>
                                        </>
                                    ) : (
                                        <button
                                            className="users-danger"
                                            onClick={() => setDeleteConfirming(user.id)}
                                            disabled={busyId !== null || user.id === currentUser?.id}
                                            title={user.id === currentUser?.id ? 'Das eigene Konto kann nicht gelöscht werden.' : ''}
                                        >
                                            Löschen
                                        </button>
                                    )}
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>

            {audit.length > 0 && (
                <div className="users-audit">
                    <h3>Letzte Änderungen</h3>
                    <ul>
                        {audit.map((entry, index) => (
                            <li key={`${entry.createdAt}-${index}`}>
                                <b>{formatDateTime(entry.createdAt)}</b>
                                <span>
                                    {entry.actor} · {describeAction(entry.action)} · {entry.subject}
                                </span>
                            </li>
                        ))}
                    </ul>
                </div>
            )}
        </section>
    );
}

function RolePermissions({ roles, selected }: { roles: RoleOption[]; selected: Role }) {
    const role = roles.find((candidate) => candidate.value === selected);

    if (!role) return null;

    return (
        <div className="users-permissions">
            <b>Diese Rolle darf zusätzlich:</b>
            {role.permissions.length === 0 ? (
                <span>nur die allgemeinen Büroansichten</span>
            ) : (
                <ul>
                    {role.permissions.map((permission) => (
                        <li key={permission}>{permission}</li>
                    ))}
                </ul>
            )}
        </div>
    );
}

function describeAction(action: string): string {
    switch (action) {
        case 'user.create':
            return 'angelegt';
        case 'user.update':
            return 'geändert';
        case 'user.delete':
            return 'gelöscht';
        case 'user.password':
            return 'Passwort zurückgesetzt';
        case 'password.self':
            return 'eigenes Passwort geändert';
        default:
            return action;
    }
}
