import { query, transaction } from '@zen/core/database';
import { generateId } from './password.js';
import { getRegisteredPermissionKeys } from './permissions-registry.js';

export async function listRoles() {
  const result = await query(
    `SELECT r.*,
       COUNT(DISTINCT rp.permission_key)::int AS permission_count,
       COUNT(DISTINCT ur.user_id)::int AS user_count
     FROM zen_auth_roles r
     LEFT JOIN zen_auth_role_permissions rp ON rp.role_id = r.id
     LEFT JOIN zen_auth_user_roles ur ON ur.role_id = r.id
     GROUP BY r.id
     ORDER BY r.created_at ASC`
  );
  return result.rows;
}

export async function getRoleById(id) {
  const roleResult = await query(
    `SELECT * FROM zen_auth_roles WHERE id = $1`,
    [id]
  );
  if (roleResult.rows.length === 0) return null;

  const permsResult = await query(
    `SELECT permission_key FROM zen_auth_role_permissions WHERE role_id = $1`,
    [id]
  );

  return {
    ...roleResult.rows[0],
    permission_keys: permsResult.rows.map(r => r.permission_key)
  };
}

export async function createRole({ name, description = null, color = '#6b7280' }) {
  if (!name || !name.trim()) throw new Error('Role name is required');

  const id = generateId();
  const result = await query(
    `INSERT INTO zen_auth_roles (id, name, description, color, is_system)
     VALUES ($1, $2, $3, $4, false)
     RETURNING *`,
    [id, name.trim(), description || null, color]
  );
  return result.rows[0];
}

export async function updateRole(roleId, { name, description, color, permissionKeys }) {
  const role = await query(`SELECT is_system FROM zen_auth_roles WHERE id = $1`, [roleId]);
  if (role.rows.length === 0) throw new Error('Role not found');

  const isSystem = role.rows[0].is_system;

  return transaction(async (client) => {
    const updateFields = [];
    const values = [];
    let idx = 1;

    if (name !== undefined) {
      if (!name.trim()) throw new Error('Role name cannot be empty');
      updateFields.push(`name = $${idx++}`);
      values.push(name.trim());
    }
    if (description !== undefined) {
      updateFields.push(`description = $${idx++}`);
      values.push(description || null);
    }
    if (color !== undefined) {
      updateFields.push(`color = $${idx++}`);
      values.push(color);
    }
    updateFields.push(`updated_at = $${idx++}`);
    values.push(new Date());
    values.push(roleId);

    const updated = await client.query(
      `UPDATE zen_auth_roles SET ${updateFields.join(', ')} WHERE id = $${idx} RETURNING *`,
      values
    );

    if (!isSystem && permissionKeys !== undefined) {
      const validKeys = getRegisteredPermissionKeys();
      const safeKeys = [...new Set(permissionKeys)].filter(k => validKeys.has(k));
      await client.query(`DELETE FROM zen_auth_role_permissions WHERE role_id = $1`, [roleId]);
      for (const key of safeKeys) {
        await client.query(
          `INSERT INTO zen_auth_role_permissions (role_id, permission_key) VALUES ($1, $2)`,
          [roleId, key]
        );
      }
    }

    const perms = await client.query(
      `SELECT permission_key FROM zen_auth_role_permissions WHERE role_id = $1`,
      [roleId]
    );

    return {
      ...updated.rows[0],
      permission_keys: perms.rows.map(r => r.permission_key)
    };
  });
}

export async function deleteRole(roleId) {
  const result = await query(`SELECT is_system FROM zen_auth_roles WHERE id = $1`, [roleId]);
  if (result.rows.length === 0) throw new Error('Role not found');
  if (result.rows[0].is_system) throw new Error('Cannot delete a system role');

  await query(`DELETE FROM zen_auth_roles WHERE id = $1`, [roleId]);
}

export async function getUserRoles(userId) {
  const result = await query(
    `SELECT r.* FROM zen_auth_roles r
     JOIN zen_auth_user_roles ur ON ur.role_id = r.id
     WHERE ur.user_id = $1
     ORDER BY r.created_at ASC`,
    [userId]
  );
  return result.rows;
}

export async function assignUserRole(userId, roleId) {
  await query(
    `INSERT INTO zen_auth_user_roles (user_id, role_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
    [userId, roleId]
  );
}

export async function revokeUserRole(userId, roleId) {
  await query(
    `DELETE FROM zen_auth_user_roles WHERE user_id = $1 AND role_id = $2`,
    [userId, roleId]
  );
}
