<?php

namespace App\Services;

use App\Models\CashRegister;
use App\Models\CashRegisterTransaction;
use App\Repositories\Eloquent\CashRegisterRepository;
use Illuminate\Support\Facades\DB;

class CashRegisterService
{
    public function __construct(
        protected CashRegisterRepository $cashRegisterRepository,
        protected LoggingService $loggingService
    ) {}

    public function getForBranch(int $branchId, int $limit = 30)
    {
        $this->loggingService->logInfo('Fetching cash registers for branch', ['branch_id' => $branchId]);
        return $this->cashRegisterRepository->getForBranch($branchId, $limit);
    }

    public function find(int $id)
    {
        $this->loggingService->logInfo('Finding cash register', ['id' => $id]);
        return $this->cashRegisterRepository->findWithTransactions($id);
    }

    public function findByDate(int $branchId, $date)
    {
        $this->loggingService->logInfo('Finding cash register by date', ['branch_id' => $branchId, 'date' => $date]);
        return $this->cashRegisterRepository->findByDate($branchId, $date);
    }

    public function getOpenRegister(int $branchId)
    {
        $this->loggingService->logInfo('Fetching open register', ['branch_id' => $branchId]);
        return $this->cashRegisterRepository->getOpenRegister($branchId);
    }

    public function openRegister(int $branchId, int $userId, float $openingBalance, $date = null)
    {
        $this->loggingService->logInfo('Opening cash register', [
            'branch_id' => $branchId,
            'user_id' => $userId,
            'opening_balance' => $openingBalance
        ]);

        // Check if there's already an open register for this branch
        $existingOpen = $this->cashRegisterRepository->getOpenRegister($branchId);
        if ($existingOpen) {
            return ['error' => 'A cash register is already open for this branch'];
        }

        $date = $date ?? today();

        return $this->cashRegisterRepository->getOrCreateForDate($branchId, $date, $userId, $openingBalance);
    }

    public function closeRegister(int $id, float $actualBalance, ?string $notes = null)
    {
        $this->loggingService->logInfo('Closing cash register', [
            'id' => $id,
            'actual_balance' => $actualBalance
        ]);

        $register = $this->cashRegisterRepository->find($id);
        if (!$register) {
            return null;
        }

        $register->close($actualBalance, $notes);
        return $register->fresh();
    }

    public function recordTransaction(int $registerId, string $type, float $amount, int $userId, ?string $referenceType = null, ?int $referenceId = null, ?string $notes = null)
    {
        $this->loggingService->logInfo('Recording cash register transaction', [
            'register_id' => $registerId,
            'type' => $type,
            'amount' => $amount
        ]);

        return DB::transaction(function () use ($registerId, $type, $amount, $userId, $referenceType, $referenceId, $notes) {
            $register = $this->cashRegisterRepository->find($registerId);
            if (!$register || $register->status !== CashRegister::STATUS_OPEN) {
                return null;
            }

            $transaction = $register->transactions()->create([
                'user_id' => $userId,
                'type' => $type,
                'amount' => $amount,
                'reference_type' => $referenceType,
                'reference_id' => $referenceId,
                'notes' => $notes,
            ]);

            // Update register totals (cash tray logic)
            $updateData = [];
            switch ($type) {
                case CashRegisterTransaction::TYPE_SALE:
                case CashRegisterTransaction::TYPE_BILL_PAYMENT:
                    // Money added to cash drawer (tendered amount)
                    $updateData['cash_sales'] = $register->cash_sales + $amount;
                    break;
                case CashRegisterTransaction::TYPE_EXPENSE:
                case CashRegisterTransaction::TYPE_CHANGE_GIVEN:
                    // Money removed from cash drawer (change given or expenses paid)
                    $updateData['cash_expenses'] = $register->cash_expenses + $amount;
                    break;
                case CashRegisterTransaction::TYPE_CASH_IN:
                    // Additional money added to drawer
                    $updateData['cash_sales'] = $register->cash_sales + $amount;
                    break;
                case CashRegisterTransaction::TYPE_CASH_OUT:
                    // Money removed from drawer
                    $updateData['cash_expenses'] = $register->cash_expenses + $amount;
                    break;
            }

            if (!empty($updateData)) {
                $this->cashRegisterRepository->update($registerId, $updateData);
                $register->refresh();
                $register->updateExpectedBalance();
            }

            return $transaction;
        });
    }

    public function recordCashIn(int $registerId, float $amount, int $userId, ?string $notes = null)
    {
        return $this->recordTransaction(
            $registerId,
            CashRegisterTransaction::TYPE_CASH_IN,
            $amount,
            $userId,
            null,
            null,
            $notes
        );
    }

    public function recordCashOut(int $registerId, float $amount, int $userId, ?string $notes = null)
    {
        return $this->recordTransaction(
            $registerId,
            CashRegisterTransaction::TYPE_CASH_OUT,
            $amount,
            $userId,
            null,
            null,
            $notes
        );
    }

    // Alias methods for controller compatibility
    public function getAllRegisters(array $filters = [])
    {
        $this->loggingService->logInfo('Fetching all cash registers', ['filters' => $filters]);
        if (isset($filters['branch_id'])) {
            return $this->getForBranch($filters['branch_id']);
        }
        return $this->cashRegisterRepository->all();
    }

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

    public function getCurrentOpenRegister(int $branchId)
    {
        return $this->getOpenRegister($branchId);
    }

    public function getRegisterSummary(int $id)
    {
        $register = $this->find($id);
        if (!$register) {
            return null;
        }

        return [
            'register' => $register,
            'opening_balance' => $register->opening_balance,
            'cash_sales' => $register->cash_sales,
            'cash_expenses' => $register->cash_expenses,
            'cash_in' => $register->cash_in,
            'cash_out' => $register->cash_out,
            'expected_balance' => $register->calculateExpectedBalance(),
            'actual_balance' => $register->actual_balance,
            'variance' => $register->variance,
            'status' => $register->status,
        ];
    }

    // Simple transaction recording for controller (4 params version)
    public function recordSimpleTransaction(int $registerId, string $type, float $amount, ?string $notes = null)
    {
        return $this->recordTransaction($registerId, $type, $amount, auth()->id(), null, null, $notes);
    }
}
