import { randomBytes } from 'node:crypto';
import {
  auditLog, createAuthToken, createUser, deleteUser, getLoginHistory, getUser, getUserByEmail,
  getUsers, setPassword, updateUser, validatePasswordStrength,
} from '../../core/identity/identity-store.mjs';
import { permissionsForRole, getRoleDefinitions } from '../../../lib/security.mjs';
import { PlatformError } from '../../kernel/errors.mjs';

const ROLES = new Set(['admin', 'manager', 'editor', 'publisher', 'viewer']);

function fail(message, status = 400, code = 'USER_OPERATION_FAILED') {
  throw new PlatformError(message, { status, code, expose: true });
}

function publicUser(user) {
  if (!user) return null;
  const { password_hash: _passwordHash, ...safe } = user;
  return safe;
}

export function createUsersService() {
  return Object.freeze({
    list() { return getUsers().map(publicUser); },
    find(id) { return publicUser(getUser(id)); },
    findByEmail(email) { return publicUser(getUserByEmail(email)); },
    currentIdentity(userId, csrf) {
      const user = getUser(userId);
      if (!user) fail('Benutzer nicht gefunden.', 404, 'USER_NOT_FOUND');
      const initials = (user.name || user.email).split(/[\s@]/).map(word => word[0]?.toUpperCase()).filter(Boolean).slice(0, 2).join('');
      return {
        id: user.id, email: user.email, name: user.name, role: user.role,
        avatar_color: user.avatar_color, initials, permissions: [...permissionsForRole(user.role)],
        role_definition: getRoleDefinitions().find(role => role.key === user.role) || null,
        csrf,
      };
    },
    updateProfile(userId, data) {
      const updated = updateUser(userId, { name: data.name });
      if (!updated) fail('Benutzer nicht gefunden.', 404, 'USER_NOT_FOUND');
      return publicUser(updated);
    },
    prepareInvite({ email, name, role, method, createdBy }) {
      const normalizedRole = ROLES.has(role) ? role : 'editor';
      if (getUserByEmail(email)) fail('User existiert bereits', 400, 'USER_EXISTS');
      if (method === 'auto_password') {
        const password = `Vd!${randomBytes(9).toString('base64url')}9a`;
        const user = createUser(email, name || email.split('@')[0], normalizedRole, createdBy, password);
        return { mode: 'auto_password', user: publicUser(user), password, role: normalizedRole };
      }
      const invite = createAuthToken(email, 'invite', normalizedRole, createdBy);
      return { mode: 'magic_link', invite, email, name: name || '', role: normalizedRole };
    },
    resendInvite({ userId, createdBy }) {
      const user = getUser(userId);
      if (!user) fail('User nicht gefunden', 404, 'USER_NOT_FOUND');
      return { user: publicUser(user), invite: createAuthToken(user.email, 'invite', user.role, createdBy) };
    },
    updateManagedUser({ actor, userId, patch }) {
      const existing = getUser(userId);
      if (!existing) fail('User nicht gefunden', 404, 'USER_NOT_FOUND');
      if (Number(actor.id) === Number(userId) && patch.role && patch.role !== 'admin') fail('Du kannst dir selbst nicht die Admin-Rolle entziehen');
      const activeAdmins = getUsers().filter(user => user.role === 'admin' && user.active).length;
      const removesLastAdmin = existing.role === 'admin' && existing.active && activeAdmins <= 1
        && ((patch.role && patch.role !== 'admin') || Number(patch.active) === 0);
      if (removesLastAdmin) fail('Der letzte aktive Administrator darf nicht deaktiviert oder herabgestuft werden.');
      const normalized = {};
      if (patch.name !== undefined) normalized.name = patch.name;
      if (patch.role !== undefined) normalized.role = ROLES.has(patch.role) ? patch.role : 'viewer';
      if (patch.active !== undefined) normalized.active = Number(patch.active) === 0 ? 0 : 1;
      if (patch.avatar_color !== undefined) normalized.avatar_color = patch.avatar_color;
      return publicUser(updateUser(userId, normalized));
    },
    deleteManagedUser({ actor, userId }) {
      if (Number(actor.id) === Number(userId)) fail('Du kannst dich nicht selbst löschen');
      const user = getUser(userId);
      if (!user) fail('User nicht gefunden', 404, 'USER_NOT_FOUND');
      if (user.role === 'admin' && user.active && getUsers().filter(entry => entry.role === 'admin' && entry.active).length <= 1) {
        fail('Der letzte aktive Administrator darf nicht gelöscht werden.');
      }
      deleteUser(userId);
      return publicUser(user);
    },
    resetPassword({ userId, password }) {
      const check = validatePasswordStrength(password);
      if (!check.valid) fail(`Passwort benötigt ${check.problems.join(', ')}.`, 400, 'PASSWORD_WEAK');
      const user = getUser(userId);
      if (!user) fail('User nicht gefunden', 404, 'USER_NOT_FOUND');
      setPassword(userId, password);
      return publicUser(user);
    },
    loginHistory(userId, limit = 30) { return getLoginHistory(userId, limit); },
    health() { return { ok: true, users: getUsers().length }; },
    auditLog,
  });
}
