<?php
namespace App\Services;

use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\Product;
use App\Models\PaymentMethod;
use App\Models\Payment;
use App\Services\InventoryService;
use App\Services\PaymentService;
use Illuminate\Support\Facades\DB;

class SalesService
{
    protected InventoryService $inventory;
    protected PaymentService $payments;

    public function __construct(InventoryService $inventory, PaymentService $payments)
    {
        $this->inventory = $inventory;
        $this->payments = $payments;
    }

    /**
     * Create a sale from payload.
     * Payload must include:
     * - items: [{product_id, qty, unit_price}]
     * - is_prices_tax_inclusive: boolean (true = entered prices include VAT)
     * - payment_method_id (optional)
     */
    public function createSaleFromPayload($user, array $payload): Sale
    {
        $items = $payload['items'];
        $customerId = $payload['customer_id'] ?? null;
        $isPricesTaxInclusive = $payload['is_prices_tax_inclusive'] ?? false;
        $paymentMethodId = $payload['payment_method_id'] ?? null;
        $paymentAmount = $payload['payment_amount'] ?? null;

        return DB::transaction(function() use ($user,$items,$customerId,$isPricesTaxInclusive,$paymentMethodId,$paymentAmount,$payload) {
            // generate receipt number (atomic)
            $receiptNo = $this->generateReceiptNumber();

            $sale = Sale::create([
                'receipt_no' => $receiptNo,
                'customer_id' => $customerId,
                'user_id' => $user->id,
                'subtotal' => 0,
                'tax_total' => 0,
                'discount' => 0,
                'grand_total' => 0,
                'is_vat_applied' => true
            ]);

            $runningSubtotal = 0.0;
            $runningTaxTotal = 0.0;

            foreach ($items as $it) {
                $product = Product::lockForUpdate()->findOrFail($it['product_id']);
                $qty = (int)$it['qty'];
                $enteredUnitPrice = (float)$it['unit_price'];

                // determine tax rate
                $taxRate = 0.0;
                if ($product->tax_id && $product->tax) {
                    $taxRate = (float)$product->tax->rate;
                }

                // compute net price and tax per unit
                if ($isPricesTaxInclusive && $taxRate > 0) {
                    $priceExTax = $enteredUnitPrice / (1 + ($taxRate / 100));
                    $taxPerUnit = $enteredUnitPrice - $priceExTax;
                } else {
                    $priceExTax = $enteredUnitPrice;
                    $taxPerUnit = $priceExTax * ($taxRate / 100);
                }

                // round values
                $priceExTax = round($priceExTax, 2);
                $taxPerUnit = round($taxPerUnit, 2);

                // totals
                $lineNetTotal = round($priceExTax * $qty, 2);
                $lineTaxTotal = round($taxPerUnit * $qty, 2);

                if ($product->stock < $qty) {
                    throw new \Exception("Insufficient stock for product {$product->sku}");
                }

                $this->inventory->decrease($product->id, $qty, 'sale', $sale->id);

                $sale->items()->create([
                    'product_id' => $product->id,
                    'qty' => $qty,
                    'price' => $enteredUnitPrice,
                    'price_ex_tax' => $priceExTax,
                    'tax_rate' => $taxRate,
                    'tax_amount' => $lineTaxTotal,
                    'total' => $lineNetTotal + $lineTaxTotal
                ]);

                $runningSubtotal += $lineNetTotal;
                $runningTaxTotal += $lineTaxTotal;
            }

            $grandTotal = round($runningSubtotal + $runningTaxTotal, 2);

            $sale->update([
                'subtotal' => round($runningSubtotal, 2),
                'tax_total' => round($runningTaxTotal, 2),
                'grand_total' => $grandTotal,
            ]);

            if ($paymentAmount && $paymentMethodId) {
                $this->payments->record(
                    $sale->id,
                    $paymentMethodId,
                    $paymentAmount,
                    $payload['payment_reference'] ?? null,
                    $user
                );
            }

            return $sale;
        }, 5);
    }

    protected function generateReceiptNumber(): string
    {
        $prefix = config('app.name', 'POS');
        return DB::transaction(function() use ($prefix) {
            $r = DB::table('receipt_sequences')->where('prefix',$prefix)->lockForUpdate()->first();
            if (!$r) {
                DB::table('receipt_sequences')->insert([
                    'prefix'=>$prefix,
                    'last'=>1,
                    'created_at'=>now(),
                    'updated_at'=>now()
                ]);
                $num = 1;
            } else {
                $num = $r->last + 1;
                DB::table('receipt_sequences')->where('prefix',$prefix)->update([
                    'last'=>$num,
                    'updated_at'=>now()
                ]);
            }
            $date = date('Ymd');
            return "{$prefix}-{$date}-".str_pad($num, 5, '0', STR_PAD_LEFT);
        });
    }
}
