<?php

namespace App\Services;

use App\Models\Sales\HeldSale;
use App\Models\Sales\HeldSaleItem;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

/**
 * Suspends a POS cart so the cashier can serve another customer, then
 * resumes it later. A held sale is a snapshot, not an invoice — no stock
 * movement and no accounting entries happen until the sale is actually
 * completed at checkout.
 */
class HeldSaleService
{
    public function __construct(private readonly DocumentNumberService $numbers) {}

    /**
     * @param  array{branch_id:int, till_id?:int|null, pos_session_id?:int|null, customer_id?:int|null, discount_type?:string|null, discount_value?:float, note?:string|null}  $header
     * @param  array<int,array{product_id?:int|null, product_bundle_id?:int|null, product_name:string, quantity:float, unit_price:float, vat_rate?:float, discount_type?:string|null, discount_value?:float, stock_batch_id?:int|null, serial_ids?:array<int,int>|null}>  $lines
     */
    public function hold(array $header, array $lines): HeldSale
    {
        return DB::transaction(function () use ($header, $lines) {
            $heldSale = HeldSale::create([
                'reference' => $this->numbers->next('held_sale'),
                'branch_id' => $header['branch_id'],
                'till_id' => $header['till_id'] ?? null,
                'pos_session_id' => $header['pos_session_id'] ?? null,
                'customer_id' => $header['customer_id'] ?? null,
                'discount_type' => $header['discount_type'] ?? null,
                'discount_value' => (float) ($header['discount_value'] ?? 0),
                'note' => $header['note'] ?? null,
                'held_at' => now(),
                'created_by' => Auth::id(),
            ]);

            foreach ($lines as $line) {
                HeldSaleItem::create([
                    'held_sale_id' => $heldSale->id,
                    'product_id' => $line['product_id'] ?? null,
                    'product_bundle_id' => $line['product_bundle_id'] ?? null,
                    'product_name' => $line['product_name'],
                    'quantity' => $line['quantity'],
                    'unit_price' => $line['unit_price'],
                    'vat_rate' => $line['vat_rate'] ?? 0,
                    'discount_type' => $line['discount_type'] ?? null,
                    'discount_value' => (float) ($line['discount_value'] ?? 0),
                    'stock_batch_id' => $line['stock_batch_id'] ?? null,
                    'selected_serial_ids' => $line['serial_ids'] ?? null,
                ]);
            }

            AuditLog::record('held_sale.created', $heldSale, [
                'reference' => $heldSale->reference,
                'items' => count($lines),
            ]);

            return $heldSale->load('items');
        });
    }

    /**
     * Return the cart-shape payload the frontend needs to restore the sale,
     * then remove it — resuming is a one-shot pop, not a repeatable peek, so
     * a resumed sale never lingers in the held list.
     *
     * @return array{header: array<string,mixed>, items: array<int,array<string,mixed>>}
     */
    public function resume(HeldSale $heldSale): array
    {
        $heldSale->load('items');

        $payload = [
            'header' => [
                'customer_id' => $heldSale->customer_id,
                'discount_type' => $heldSale->discount_type,
                'discount_value' => (float) $heldSale->discount_value,
            ],
            'items' => $heldSale->items->map(fn (HeldSaleItem $item) => [
                'product_id' => $item->product_id,
                'product_bundle_id' => $item->product_bundle_id,
                'product_name' => $item->product_name,
                'quantity' => (float) $item->quantity,
                'unit_price' => (float) $item->unit_price,
                'vat_rate' => (float) $item->vat_rate,
                'discount_type' => $item->discount_type,
                'discount_value' => (float) $item->discount_value,
                'stock_batch_id' => $item->stock_batch_id,
                'serial_ids' => $item->selected_serial_ids,
            ])->values()->all(),
        ];

        AuditLog::record('held_sale.resumed', $heldSale, ['reference' => $heldSale->reference]);

        $heldSale->delete();

        return $payload;
    }

    public function discard(HeldSale $heldSale): void
    {
        AuditLog::record('held_sale.discarded', $heldSale, [
            'reference' => $heldSale->reference,
            'items' => $heldSale->items()->count(),
        ]);

        $heldSale->delete();
    }
}
