const mongoose = require('mongoose');
const Employee = require('../models/Employee');
const Department = require('../models/Department');

function validateEmployeeBody(body) {
  const requiredStringFields = ['employeeNumber', 'firstName', 'lastName', 'address', 'position', 'telephone', 'gender', 'hiredDate', 'department'];
  for (const f of requiredStringFields) {
    if (body == null || body[f] == null) {
      return `${f} is required`;
    }
  }

  if (typeof body.employeeNumber !== 'string' || body.employeeNumber.trim().length < 2) return 'employeeNumber must be at least 2 characters';
  if (typeof body.gender !== 'string' || !['Male', 'Female', 'Other'].includes(body.gender)) return 'gender must be one of Male, Female, Other';

  const date = new Date(body.hiredDate);
  if (Number.isNaN(date.getTime())) return 'hiredDate must be a valid date';

  if (!mongoose.Types.ObjectId.isValid(body.department)) return 'department must be a valid department id';

  return null;
}

async function createEmployee(req, res, next) {
  try {
    const errMsg = validateEmployeeBody(req.body);
    if (errMsg) return res.status(400).json({ message: errMsg });

    const existing = await Employee.findOne({ employeeNumber: req.body.employeeNumber.trim() });
    if (existing) return res.status(400).json({ message: 'employeeNumber already exists' });

    const dep = await Department.findById(req.body.department);
    if (!dep) return res.status(404).json({ message: 'Department not found' });

    const employee = await Employee.create({
      employeeNumber: req.body.employeeNumber.trim(),
      firstName: req.body.firstName.trim(),
      lastName: req.body.lastName.trim(),
      address: req.body.address.trim(),
      position: req.body.position.trim(),
      telephone: req.body.telephone.trim(),
      gender: req.body.gender,
      hiredDate: new Date(req.body.hiredDate),
      department: req.body.department
    });

    const populated = await Employee.findById(employee._id).populate('department');
    return res.status(201).json(populated);
  } catch (err) {
    return next(err);
  }
}

async function getAllEmployees(req, res, next) {
  try {
    const employees = await Employee.find().populate('department').sort({ createdAt: -1 });
    return res.status(200).json(employees);
  } catch (err) {
    return next(err);
  }
}

async function getEmployeeById(req, res, next) {
  try {
    const { id } = req.params;
    if (!mongoose.Types.ObjectId.isValid(id)) return res.status(400).json({ message: 'Invalid id' });

    const employee = await Employee.findById(id).populate('department');
    if (!employee) return res.status(404).json({ message: 'Employee not found' });
    return res.status(200).json(employee);
  } catch (err) {
    return next(err);
  }
}

async function updateEmployee(req, res, next) {
  try {
    const { id } = req.params;
    if (!mongoose.Types.ObjectId.isValid(id)) return res.status(400).json({ message: 'Invalid id' });

    const errMsg = validateEmployeeBody(req.body);
    if (errMsg) return res.status(400).json({ message: errMsg });

    const dep = await Department.findById(req.body.department);
    if (!dep) return res.status(404).json({ message: 'Department not found' });

    const other = await Employee.findOne({ employeeNumber: req.body.employeeNumber.trim(), _id: { $ne: id } });
    if (other) return res.status(400).json({ message: 'employeeNumber already exists' });

    const updated = await Employee.findByIdAndUpdate(
      id,
      {
        employeeNumber: req.body.employeeNumber.trim(),
        firstName: req.body.firstName.trim(),
        lastName: req.body.lastName.trim(),
        address: req.body.address.trim(),
        position: req.body.position.trim(),
        telephone: req.body.telephone.trim(),
        gender: req.body.gender,
        hiredDate: new Date(req.body.hiredDate),
        department: req.body.department
      },
      { new: true, runValidators: true }
    );

    if (!updated) return res.status(404).json({ message: 'Employee not found' });

    const populated = await Employee.findById(updated._id).populate('department');
    return res.status(200).json(populated);
  } catch (err) {
    return next(err);
  }
}

async function deleteEmployee(req, res, next) {
  try {
    const { id } = req.params;
    if (!mongoose.Types.ObjectId.isValid(id)) return res.status(400).json({ message: 'Invalid id' });

    const deleted = await Employee.findByIdAndDelete(id);
    if (!deleted) return res.status(404).json({ message: 'Employee not found' });

    return res.status(200).json({ message: 'Employee deleted successfully' });
  } catch (err) {
    return next(err);
  }
}

module.exports = {
  createEmployee,
  getAllEmployees,
  getEmployeeById,
  updateEmployee,
  deleteEmployee
};

