import bcrypt from 'bcryptjs';
import prisma from '../services/prisma.js';
import asyncHandler from '../utils/asyncHandler.js';
import ApiError from '../utils/ApiError.js';
import { adminCreateUserSchema, adminUpdateUserSchema } from '../utils/validators.js';

const publicSelect = {
  id: true,
  name: true,
  email: true,
  role: true,
  isActive: true,
  createdAt: true,
  _count: { select: { attempts: true, purchases: true } },
};

// GET /api/users  (admin)
export const listUsers = asyncHandler(async (req, res) => {
  const { search } = req.query;
  const where = search
    ? {
        OR: [
          { name: { contains: String(search), mode: 'insensitive' } },
          { email: { contains: String(search), mode: 'insensitive' } },
        ],
      }
    : {};
  const users = await prisma.user.findMany({
    where,
    orderBy: { createdAt: 'desc' },
    select: publicSelect,
  });
  res.json({ success: true, users });
});

// POST /api/users  (admin)
export const createUser = asyncHandler(async (req, res) => {
  const data = adminCreateUserSchema.parse(req.body);

  const existing = await prisma.user.findUnique({ where: { email: data.email.toLowerCase() } });
  if (existing) throw ApiError.conflict('A user with this email already exists');

  const passwordHash = await bcrypt.hash(data.password, 12);
  const user = await prisma.user.create({
    data: {
      name: data.name,
      email: data.email.toLowerCase(),
      passwordHash,
      role: data.role,
    },
    select: publicSelect,
  });
  res.status(201).json({ success: true, user });
});

// PATCH /api/users/:id  (admin) — update name / role / password / active status
export const updateUser = asyncHandler(async (req, res) => {
  const data = adminUpdateUserSchema.parse(req.body);

  const target = await prisma.user.findUnique({ where: { id: req.params.id } });
  if (!target) throw ApiError.notFound('User not found');

  // The super admin account is protected: its role can never be changed.
  if (target.role === 'SUPER_ADMIN' && data.role && data.role !== 'SUPER_ADMIN') {
    throw ApiError.forbidden('The super admin role cannot be changed');
  }
  // Prevent the super admin from changing their own role and locking themselves out.
  if (target.id === req.user.id && data.role && data.role !== req.user.role) {
    throw ApiError.badRequest('You cannot change your own role');
  }
  // The super admin can never be deactivated, and you can't deactivate yourself.
  if (data.isActive === false) {
    if (target.role === 'SUPER_ADMIN') {
      throw ApiError.forbidden('The super admin account cannot be deactivated');
    }
    if (target.id === req.user.id) {
      throw ApiError.badRequest('You cannot deactivate your own account');
    }
  }

  const patch = {};
  if (data.name) patch.name = data.name;
  if (data.role) patch.role = data.role;
  if (typeof data.isActive === 'boolean') patch.isActive = data.isActive;
  if (data.password) patch.passwordHash = await bcrypt.hash(data.password, 12);

  const user = await prisma.user.update({
    where: { id: req.params.id },
    data: patch,
    select: publicSelect,
  });
  res.json({ success: true, user });
});

// DELETE /api/users/:id  (admin)
export const deleteUser = asyncHandler(async (req, res) => {
  if (req.params.id === req.user.id) {
    throw ApiError.badRequest('You cannot delete your own account');
  }
  const target = await prisma.user.findUnique({ where: { id: req.params.id } });
  if (!target) throw ApiError.notFound('User not found');
  if (target.role === 'SUPER_ADMIN') {
    throw ApiError.forbidden('The super admin account cannot be deleted');
  }

  await prisma.user.delete({ where: { id: req.params.id } });
  res.json({ success: true, message: 'User deleted' });
});
