import mongoose from 'mongoose';
import Expense, { EXPENSE_CATEGORIES } from '../models/Expense.js';
import logAudit from '../utils/audit.js';

const buildFilter = (query = {}) => {
  const filter = {};
  if (query.from || query.to) {
    filter.expenseDate = {};
    if (query.from) filter.expenseDate.$gte = new Date(query.from);
    if (query.to) {
      const to = new Date(query.to);
      to.setHours(23, 59, 59, 999);
      filter.expenseDate.$lte = to;
    }
  }
  if (query.category) filter.category = query.category;
  if (query.paymentMethod) filter.paymentMethod = query.paymentMethod;
  return filter;
};

const listExpenses = async (query = {}) => {
  const page = Math.max(Number(query.page) || 1, 1);
  const limit = Math.min(Number(query.limit) || 20, 100);
  const filter = buildFilter(query);
  const [items, total, totals] = await Promise.all([
    Expense.find(filter).sort({ expenseDate: -1 }).skip((page - 1) * limit).limit(limit),
    Expense.countDocuments(filter),
    Expense.aggregate([{ $match: filter }, { $group: { _id: null, total: { $sum: '$amount' }, count: { $sum: 1 } } }]),
  ]);
  return { items, total, totalAmount: totals[0]?.total || 0, page, limit };
};

const createExpense = async (data, req) => {
  if (!EXPENSE_CATEGORIES.includes(data.category)) {
    throw Object.assign(new Error(`Category must be one of: ${EXPENSE_CATEGORIES.join(', ')}`), { statusCode: 400 });
  }
  const amount = Number(data.amount);
  if (!amount || amount <= 0) {
    throw Object.assign(new Error('Amount must be greater than zero'), { statusCode: 400 });
  }
  const expense = await Expense.create({
    ...data,
    amount,
    createdBy: req.user ? { id: req.user._id, name: req.user.name } : { id: null, name: '' },
  });
  logAudit(req, 'EXPENSE_CREATED', 'expense', expense._id, {
    category: expense.category,
    amount: expense.amount,
  });
  return expense;
};

const updateExpense = async (id, data, req) => {
  const expense = await Expense.findById(id);
  if (!expense) throw Object.assign(new Error('Expense not found'), { statusCode: 404 });
  const updatable = [
    'expenseDate',
    'category',
    'subcategory',
    'amount',
    'paymentMethod',
    'vendor',
    'referenceNumber',
    'description',
    'attachment',
    'notes',
  ];
  for (const key of updatable) {
    if (data[key] !== undefined) expense[key] = data[key];
  }
  await expense.save();
  logAudit(req, 'EXPENSE_UPDATED', 'expense', expense._id, { category: expense.category, amount: expense.amount });
  return expense;
};

const deleteExpense = async (id, req) => {
  const expense = await Expense.findByIdAndDelete(id);
  if (!expense) throw Object.assign(new Error('Expense not found'), { statusCode: 404 });
  logAudit(req, 'EXPENSE_DELETED', 'expense', expense._id, { category: expense.category, amount: expense.amount });
  return expense;
};

export default { listExpenses, createExpense, updateExpense, deleteExpense };
