<?php

namespace App\Services;

use App\Models\Expense;
use App\Models\CashRegister;
use App\Models\CashRegisterTransaction;
use App\Repositories\Eloquent\ExpenseRepository;
use App\Repositories\Eloquent\ExpenseCategoryRepository;

class ExpenseService
{
    public function __construct(
        protected ExpenseRepository $expenseRepository,
        protected ExpenseCategoryRepository $categoryRepository,
        protected CashRegisterService $cashRegisterService,
        protected LoggingService $loggingService
    ) {}

    // Categories
    public function getAllCategories(bool $activeOnly = false)
    {
        $this->loggingService->logInfo('Fetching all expense categories', ['active_only' => $activeOnly]);
        if ($activeOnly) {
            return $this->categoryRepository->getActive();
        }
        return $this->categoryRepository->all();
    }

    public function getActiveCategories()
    {
        $this->loggingService->logInfo('Fetching active expense categories');
        return $this->categoryRepository->getActive();
    }

    public function findCategory(int $id)
    {
        return $this->categoryRepository->find($id);
    }

    public function createCategory(array $data)
    {
        $this->loggingService->logInfo('Creating expense category', ['data' => $data]);
        return $this->categoryRepository->create($data);
    }

    public function updateCategory(int $id, array $data)
    {
        $this->loggingService->logInfo('Updating expense category', ['id' => $id, 'data' => $data]);
        return $this->categoryRepository->update($id, $data);
    }

    public function deleteCategory(int $id)
    {
        $this->loggingService->logInfo('Deleting expense category', ['id' => $id]);
        return $this->categoryRepository->delete($id);
    }

    // Expenses
    public function getAll()
    {
        $this->loggingService->logInfo('Fetching all expenses');
        return $this->expenseRepository->all();
    }

    public function getForBranch(int $branchId)
    {
        $this->loggingService->logInfo('Fetching expenses for branch', ['branch_id' => $branchId]);
        return $this->expenseRepository->getForBranch($branchId);
    }

    public function getByStatus(int $branchId, string $status)
    {
        $this->loggingService->logInfo('Fetching expenses by status', [
            'branch_id' => $branchId,
            'status' => $status
        ]);
        return $this->expenseRepository->getByStatus($branchId, $status);
    }

    public function getPending(int $branchId)
    {
        $this->loggingService->logInfo('Fetching pending expenses', ['branch_id' => $branchId]);
        return $this->expenseRepository->getPending($branchId);
    }

    public function getByDateRange(int $branchId, $startDate, $endDate)
    {
        $this->loggingService->logInfo('Fetching expenses by date range', [
            'branch_id' => $branchId,
            'start_date' => $startDate,
            'end_date' => $endDate
        ]);
        return $this->expenseRepository->getByDateRange($branchId, $startDate, $endDate);
    }

    public function find(int $id)
    {
        $this->loggingService->logInfo('Finding expense', ['id' => $id]);
        return $this->expenseRepository->findWithRelations($id);
    }

    public function create(array $data)
    {
        $this->loggingService->logInfo('Creating expense', ['data' => $data]);
        return $this->expenseRepository->create($data);
    }

    public function update(int $id, array $data)
    {
        $this->loggingService->logInfo('Updating expense', ['id' => $id, 'data' => $data]);
        return $this->expenseRepository->update($id, $data);
    }

    public function delete(int $id)
    {
        $this->loggingService->logInfo('Deleting expense', ['id' => $id]);
        return $this->expenseRepository->delete($id);
    }

    public function approve(int $id, int $approverId)
    {
        $this->loggingService->logInfo('Approving expense', ['id' => $id, 'approver_id' => $approverId]);

        $expense = $this->expenseRepository->update($id, [
            'status' => Expense::STATUS_APPROVED,
            'approved_by' => $approverId,
            'approved_at' => now(),
        ]);

        // If it's a cash expense from cash tray, record in cash register
        if ($expense && $expense->payment_method === 'cash' && $expense->payment_source === Expense::PAYMENT_SOURCE_CASH_TRAY) {
            $this->recordExpenseInCashRegister($expense);
        }

        return $expense;
    }

    public function reject(int $id, int $approverId, ?string $reason = null)
    {
        $this->loggingService->logInfo('Rejecting expense', ['id' => $id, 'approver_id' => $approverId]);
        return $this->expenseRepository->update($id, [
            'status' => Expense::STATUS_REJECTED,
            'approved_by' => $approverId,
            'approved_at' => now(),
            'rejection_reason' => $reason,
        ]);
    }

    public function getSummaryByCategory(int $branchId, $startDate, $endDate)
    {
        $this->loggingService->logInfo('Fetching expense summary by category', [
            'branch_id' => $branchId,
            'start_date' => $startDate,
            'end_date' => $endDate
        ]);
        return $this->expenseRepository->getSummaryByCategory($branchId, $startDate, $endDate);
    }

    // Alias methods for controller compatibility
    public function approveExpense(int $id, int $approverId)
    {
        return $this->approve($id, $approverId);
    }

    public function rejectExpense(int $id, int $approverId, ?string $reason = null)
    {
        return $this->reject($id, $approverId, $reason);
    }

    public function deleteExpense(int $id)
    {
        return $this->delete($id);
    }

    public function getAllExpenses(array $filters = [])
    {
        $this->loggingService->logInfo('Fetching all expenses with filters', ['filters' => $filters]);

        if (isset($filters['branch_id'])) {
            return $this->getForBranch($filters['branch_id']);
        }

        return $this->getAll();
    }

    // Additional alias methods for controller compatibility
    public function getCategoryById(int $id)
    {
        return $this->findCategory($id);
    }

    public function getExpenseById(int $id)
    {
        return $this->find($id);
    }

    public function createExpense(array $data)
    {
        // Add the authenticated user's ID if not provided
        if (!isset($data['user_id'])) {
            $data['user_id'] = auth()->id();
        }

        // Default payment_source to 'self' if not provided
        if (!isset($data['payment_source'])) {
            $data['payment_source'] = Expense::PAYMENT_SOURCE_SELF;
        }

        $expense = $this->create($data);

        // If it's a cash expense from cash tray and already approved, record in cash register
        if ($expense->payment_method === 'cash' &&
            $expense->payment_source === Expense::PAYMENT_SOURCE_CASH_TRAY &&
            $expense->status === Expense::STATUS_APPROVED) {
            $this->recordExpenseInCashRegister($expense);
        }

        return $expense;
    }

    public function updateExpense(int $id, array $data)
    {
        return $this->update($id, $data);
    }

    /**
     * Record expense in cash register
     */
    private function recordExpenseInCashRegister(Expense $expense): void
    {
        // Find open cash register for the branch
        $cashRegister = CashRegister::where('branch_id', $expense->branch_id)
            ->where('status', 'open')
            ->latest()
            ->first();

        if (!$cashRegister) {
            $this->loggingService->logWarning('No open cash register found for expense', [
                'expense_id' => $expense->id,
                'branch_id' => $expense->branch_id
            ]);
            return;
        }

        // Record expense transaction using CashRegisterService
        $this->cashRegisterService->recordTransaction(
            $cashRegister->id,
            CashRegisterTransaction::TYPE_EXPENSE,
            $expense->amount,
            $expense->user_id,
            'Expense',
            $expense->id,
            "Expense: {$expense->description} (Ref: {$expense->reference_number})"
        );

        $this->loggingService->logInfo('Expense recorded in cash register', [
            'expense_id' => $expense->id,
            'cash_register_id' => $cashRegister->id,
            'amount' => $expense->amount
        ]);
    }
}
