import mongoose from 'mongoose';
import Admin from '../models/Admin.js';
import logAudit from '../utils/audit.js';
import { permissionsFor, ROLES } from '../utils/permissions.js';

const listStaff = async (query = {}) => {
  const filter = {};
  if (query.role) filter.role = query.role;
  if (query.status) filter.status = query.status;
  if (query.search) {
    const rx = new RegExp(String(query.search).trim(), 'i');
    filter.$or = [{ name: rx }, { email: rx }, { employeeId: rx }];
  }
  const staff = await Admin.find(filter).sort({ createdAt: -1 });
  return staff;
};

const getStaff = async (id) => {
  const staff = await Admin.findById(id);
  if (!staff) throw Object.assign(new Error('Staff member not found'), { statusCode: 404 });
  return staff;
};

const createStaff = async (data, req) => {
  const { name, email, password, role } = data;
  if (!name || !email || !password || !role) {
    throw Object.assign(new Error('Name, email, password and role are required'), { statusCode: 400 });
  }
  if (!ROLES.includes(role)) {
    throw Object.assign(new Error(`Invalid role: ${role}`), { statusCode: 400 });
  }
  if (String(password).length < 6) {
    throw Object.assign(new Error('Password must be at least 6 characters'), { statusCode: 400 });
  }
  const existing = await Admin.findOne({ email: String(email).toLowerCase().trim() });
  if (existing) {
    throw Object.assign(new Error('A user with this email already exists'), { statusCode: 409 });
  }

  // Only SUPER_ADMIN may create SUPER_ADMIN/ADMIN accounts
  if (['SUPER_ADMIN', 'ADMIN'].includes(role) && req.user.role !== 'SUPER_ADMIN') {
    throw Object.assign(new Error('Only SUPER_ADMIN can create admin-level accounts'), { statusCode: 403 });
  }

  const staff = await Admin.create({
    name,
    email,
    password,
    role,
    phone: data.phone || '',
    employeeId: data.employeeId || '',
    status: data.status || 'ACTIVE',
    joiningDate: data.joiningDate || undefined,
    notes: data.notes || '',
  });

  logAudit(req, 'STAFF_CREATED', 'staff', staff._id, {
    name: staff.name,
    email: staff.email,
    role: staff.role,
  });
  return staff;
};

const updateStaff = async (id, data, req) => {
  const staff = await Admin.findById(id);
  if (!staff) throw Object.assign(new Error('Staff member not found'), { statusCode: 404 });

  if (data.role && !ROLES.includes(data.role)) {
    throw Object.assign(new Error(`Invalid role: ${data.role}`), { statusCode: 400 });
  }
  if ((data.role === 'SUPER_ADMIN' || staff.role === 'SUPER_ADMIN') && req.user.role !== 'SUPER_ADMIN') {
    throw Object.assign(new Error('Only SUPER_ADMIN can modify super admin accounts'), { statusCode: 403 });
  }
  if (staff._id.equals(req.user._id) && data.status === 'INACTIVE') {
    throw Object.assign(new Error('You cannot deactivate your own account'), { statusCode: 400 });
  }

  const before = { role: staff.role, status: staff.status };
  const updatable = ['name', 'phone', 'employeeId', 'status', 'notes', 'joiningDate', 'profileImage'];
  for (const key of updatable) {
    if (data[key] !== undefined) staff[key] = data[key];
  }
  if (data.role !== undefined) staff.role = data.role;
  if (data.password) {
    if (String(data.password).length < 6) {
      throw Object.assign(new Error('Password must be at least 6 characters'), { statusCode: 400 });
    }
    staff.password = data.password; // hashed by pre-save hook
  }
  await staff.save();

  const meta = { name: staff.name, role: staff.role };
  if (before.role !== staff.role) meta.before = before;
  logAudit(req, 'STAFF_UPDATED', 'staff', staff._id, meta);
  return staff;
};

const setStatus = async (id, status, req) => {
  const staff = await Admin.findById(id);
  if (!staff) throw Object.assign(new Error('Staff member not found'), { statusCode: 404 });
  if (!['ACTIVE', 'INACTIVE'].includes(status)) {
    throw Object.assign(new Error('Invalid status'), { statusCode: 400 });
  }
  if (staff._id.equals(req.user._id)) {
    throw Object.assign(new Error('You cannot change your own account status'), { statusCode: 400 });
  }
  if (staff.role === 'SUPER_ADMIN' && req.user.role !== 'SUPER_ADMIN') {
    throw Object.assign(new Error('Only SUPER_ADMIN can modify super admin accounts'), { statusCode: 403 });
  }
  staff.status = status;
  await staff.save();
  logAudit(req, status === 'INACTIVE' ? 'STAFF_DEACTIVATED' : 'STAFF_ACTIVATED', 'staff', staff._id, {
    name: staff.name,
  });
  return staff;
};

const deleteStaff = async (id, req) => {
  const staff = await Admin.findById(id);
  if (!staff) throw Object.assign(new Error('Staff member not found'), { statusCode: 404 });
  if (staff.role === 'SUPER_ADMIN') {
    throw Object.assign(new Error('Super admin accounts cannot be deleted'), { statusCode: 400 });
  }
  if (staff._id.equals(req.user._id)) {
    throw Object.assign(new Error('You cannot delete your own account'), { statusCode: 400 });
  }
  await staff.deleteOne();
  logAudit(req, 'STAFF_DELETED', 'staff', staff._id, { name: staff.name, email: staff.email });
  return staff;
};

const getPermissionsMatrix = (role) => ({
  role,
  permissions: permissionsFor(role),
});

export default {
  listStaff,
  getStaff,
  createStaff,
  updateStaff,
  setStatus,
  deleteStaff,
  getPermissionsMatrix,
};
