<?php

namespace App\Core\Repositories;

use App\Models\Expense;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * Expense Repository
 * Handles all database operations for expenses
 */
class ExpenseRepository
{
    /**
     * Get all expenses
     */
    public function getAll(): Collection
    {
        return Expense::with(['account', 'vendor', 'creator'])->get();
    }

    /**
     * Get paginated expenses
     */
    public function getPaginated(int $perPage = 15, array $filters = []): LengthAwarePaginator
    {
        $query = Expense::with(['account', 'vendor', 'creator']);

        if (isset($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        if (isset($filters['account_id'])) {
            $query->where('account_id', $filters['account_id']);
        }

        if (isset($filters['vendor_id'])) {
            $query->where('vendor_id', $filters['vendor_id']);
        }

        if (isset($filters['date_from'])) {
            $query->where('expense_date', '>=', $filters['date_from']);
        }

        if (isset($filters['date_to'])) {
            $query->where('expense_date', '<=', $filters['date_to']);
        }

        return $query->orderBy('expense_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->paginate($perPage);
    }

    /**
     * Get expense by ID
     */
    public function getById(int $id): ?Expense
    {
        return Expense::with(['account', 'vendor', 'creator', 'approver'])->find($id);
    }

    /**
     * Create a new expense
     */
    public function create(array $data): Expense
    {
        return Expense::create($data);
    }

    /**
     * Update an expense
     */
    public function update(Expense $expense, array $data): bool
    {
        return $expense->update($data);
    }

    /**
     * Delete an expense
     */
    public function delete(Expense $expense): bool
    {
        return $expense->delete();
    }

    /**
     * Generate next expense number
     */
    public function generateExpenseNumber(): string
    {
        $prefix = config('accounting.expense_prefix', 'EXP');
        $year = now()->year;
        $lastExpense = Expense::whereYear('created_at', $year)
            ->orderBy('id', 'desc')
            ->first();

        if ($lastExpense) {
            $lastNumber = (int) substr($lastExpense->expense_number, -6);
            $nextNumber = $lastNumber + 1;
        } else {
            $nextNumber = 1;
        }

        return $prefix.'-'.$year.'-'.str_pad($nextNumber, 6, '0', STR_PAD_LEFT);
    }

    /**
     * Get total expenses for date range
     */
    public function getTotalForDateRange(string $dateFrom, string $dateTo): float
    {
        return Expense::whereBetween('expense_date', [$dateFrom, $dateTo])
            ->where('status', '!=', 'rejected')
            ->sum('total');
    }
}
