<?php

namespace App\Services;

use App\Models\Order;
use App\Models\Payment;
use App\Models\CashRegister;
use App\Models\CashRegisterTransaction;
use App\Models\ProductionBatch;
use Illuminate\Support\Facades\DB;

class PaymentService
{
    protected $productionBatchService;
    protected $cashRegisterService;

    public function __construct(
        ProductionBatchService $productionBatchService,
        CashRegisterService $cashRegisterService
    ) {
        $this->productionBatchService = $productionBatchService;
        $this->cashRegisterService = $cashRegisterService;
    }

    /**
     * Process payment and convert temp bill to final bill
     */
    public function processPaymentAndConvert(
        Order $order,
        float $paymentAmount,
        string $paymentMethod = 'cash',
        float $tenderedAmount = null
    ): array {
        if (!$order->isTempBill() && $order->status !== Order::STATUS_AWAITING_PAYMENT) {
            throw new \Exception('This order cannot be paid');
        }

        return DB::transaction(function () use ($order, $paymentAmount, $paymentMethod, $tenderedAmount) {
            // Calculate amounts
            $totalAmount = (float) $order->total_amount;
            $actualTendered = $tenderedAmount ?? $paymentAmount;
            $changeAmount = max(0, $actualTendered - $totalAmount);
            $remainingAmount = max(0, $totalAmount - $paymentAmount);

            // Update order payment details
            $order->payment_received = $paymentAmount;
            $order->change_amount = $changeAmount;
            $order->remaining_amount = $remainingAmount;

            // Create payment record
            $payment = Payment::create([
                'order_id' => $order->id,
                'method' => $paymentMethod,
                'amount' => min($paymentAmount, $totalAmount),
                'tendered' => $actualTendered,
                'change' => $changeAmount,
                'status' => 'completed',
                'notes' => $remainingAmount > 0
                    ? "Partial payment. Remaining: {$remainingAmount}"
                    : "Full payment received",
            ]);

            // Only convert to final if fully paid
            if ($remainingAmount == 0) {
                $this->convertToFinalBill($order);

                // Deduct inventory (scoop sales)
                $this->deductInventoryForOrder($order);
            } else {
                // Keep as awaiting payment for partial payments
                $order->status = Order::STATUS_AWAITING_PAYMENT;
            }

            $order->save();

            // Update cash register (if cash payment)
            if ($paymentMethod === 'cash') {
                $this->updateCashRegister($order, $actualTendered, $changeAmount);
            }

            return [
                'order' => $order->fresh(['items.product', 'payments']),
                'payment' => $payment,
                'change_amount' => $changeAmount,
                'remaining_amount' => $remainingAmount,
                'bill_number' => $order->bill_number,
                'is_fully_paid' => $remainingAmount == 0,
            ];
        });
    }

    /**
     * Convert temp bill to final bill
     */
    private function convertToFinalBill(Order $order): void
    {
        $order->bill_type = Order::BILL_TYPE_FINAL;
        $order->is_temp_bill = false;
        $order->status = Order::STATUS_COMPLETED;
        $order->bill_number = Order::generateBillNumber($order->branch_id);
        $order->converted_to_final_at = now();
        $order->completed_at = now();
        $order->notes = str_replace('TEMP BILL - NOT PAID', 'PAID - FINAL BILL', $order->notes ?? '');
    }

    /**
     * Update cash register with payment and change
     */
    private function updateCashRegister(Order $order, float $received, float $change): void
    {
        $cashRegister = CashRegister::where('branch_id', $order->branch_id)
            ->where('status', 'open')
            ->latest()
            ->first();

        if (!$cashRegister) {
            throw new \Exception('No open cash register found. Please open a cash register first.');
        }

        // Record transaction: Cash received (tendered amount added to drawer)
        $this->cashRegisterService->recordTransaction(
            $cashRegister->id,
            CashRegisterTransaction::TYPE_BILL_PAYMENT,
            $received,
            auth()->id(),
            'Order',
            $order->id,
            "Cash received for Order #{$order->order_number}"
        );

        // Record transaction: Change given (money removed from drawer)
        if ($change > 0) {
            $this->cashRegisterService->recordTransaction(
                $cashRegister->id,
                CashRegisterTransaction::TYPE_CHANGE_GIVEN,
                $change,
                auth()->id(),
                'Order',
                $order->id,
                "Change given for Order #{$order->order_number}"
            );
        }
    }

    /**
     * Deduct inventory for order items (scoop sales)
     */
    private function deductInventoryForOrder(Order $order): void
    {
        foreach ($order->items as $item) {
            // Find size from selected_options to determine scoop count
            $scoopCount = $this->getScoopCountFromOptions($item->selected_options);

            // Find available batch and record scoop sale
            $batch = $this->productionBatchService->findAvailableBatchForProduct(
                $order->branch_id,
                $item->product_id
            );

            if ($batch) {
                $this->productionBatchService->recordScoopSale(
                    $batch->id,
                    $scoopCount * $item->quantity,
                    $order->id
                );
            }
        }
    }

    /**
     * Get scoop count from selected options
     */
    private function getScoopCountFromOptions(array $selectedOptions): int
    {
        // Map option names to scoop counts
        $scoopMapping = [
            'Small' => 1,
            'Medium' => 2,
            'Large' => 3,
            'Single' => 1,
            'Double' => 2,
            'Triple' => 3,
            '1 Scoop' => 1,
            '2 Scoops' => 2,
            '3 Scoops' => 3,
        ];

        foreach ($selectedOptions as $option) {
            if (isset($scoopMapping[$option['name']])) {
                return $scoopMapping[$option['name']];
            }
        }

        return 1; // Default to 1 scoop
    }

    /**
     * Get current cash register balance
     */
    public function getCashRegisterBalance(int $branchId): ?float
    {
        $cashRegister = CashRegister::where('branch_id', $branchId)
            ->where('status', 'open')
            ->latest()
            ->first();

        return $cashRegister ? (float) $cashRegister->calculateExpectedBalance() : null;
    }
}
