import { findAll, findById, insert, update, softDelete, findByName } from '../repositories/role.repo.js';
import { hasEmployeesWithRole } from '../repositories/employee.repo.js';
import { createWithId } from '../utils/id.js';
import { NotFoundError, ConflictError } from '../utils/errors.js';
import { emitter } from '../events/emitter.js';
import type { Role } from '../types/index.js';

export async function list(): Promise<Role[]> {
  return findAll();
}

export async function get(id: string): Promise<Role> {
  const role = await findById(id);
  if (!role) throw new NotFoundError('Role not found');
  return role;
}

export async function create(data: { name: string; permissions: string[] | '*' }, userId: string): Promise<Role> {
  const duplicate = await findByName(data.name);
  if (duplicate) throw new ConflictError(`"${data.name}" already exists`);

  const { id } = await createWithId('roles', 'ROLE', (id) => insert({ ...data, is_system: false }, id, userId));
  const role = await findById(id);
  if (!role) throw new NotFoundError('Role not found');
  emitter.emit('activity.create', { entity_type: 'role', entity_id: id, action: 'created', user_id: userId });
  return role;
}

export async function updateRole(id: string, data: { name?: string; permissions?: string[] | '*' }, userId: string): Promise<Role> {
  const existing = await findById(id);
  if (!existing) throw new NotFoundError('Role not found');
  if (data.name !== undefined) {
    const duplicate = await findByName(data.name, id);
    if (duplicate) throw new ConflictError(`"${data.name}" already exists`);
  }
  await update(id, data, userId);
  emitter.emit('activity.create', { entity_type: 'role', entity_id: id, action: 'updated', user_id: userId });
  return get(id);
}

export async function remove(id: string, userId: string): Promise<void> {
  const existing = await findById(id);
  if (!existing) throw new NotFoundError('Role not found');
  if (await hasEmployeesWithRole(id)) {
    throw new ConflictError('This role is assigned to existing employees and cannot be deleted');
  }
  await softDelete(id, userId);
  emitter.emit('activity.create', { entity_type: 'role', entity_id: id, action: 'deleted', user_id: userId });
}
