<?php

namespace App\Filament\Resources\Concerns;

use App\Filament\Forms\Components\SalesOrderProductGrid;
use App\Services\BarcodeLabelService;
use App\Services\CurrentContext;
use App\Services\SalesOrderCatalog;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Renderless;

/**
 * Serves the Sales Order product grid its branch-priced catalog on demand,
 * and resolves a scanned shop-printed label into a finished order line — the
 * two server round-trips a barcode-scanner-driven form needs. Shared by the
 * full-screen create terminal and the edit form's product grid, so a fix or a
 * permission rule here applies to both without drifting apart.
 *
 * `#[Renderless]` is the whole point of both methods: the browser asks for the
 * catalog exactly once per branch and a label scan costs exactly one lookup,
 * with neither triggering a re-render of the form. Every other interaction —
 * customer, rep, dates, payments, the note — re-renders without touching
 * either at all.
 *
 * @see SalesOrderProductGrid
 */
trait InteractsWithSalesOrderCatalog
{
    /**
     * @return array{ok: bool, branchId: int|null, products: array<int, array<string, mixed>>}
     */
    #[Renderless]
    public function salesOrderCatalog(int|string|null $branchId = null): array
    {
        abort_unless(Auth::user()?->hasPermissionTo('isms_sales_orders.access') ?? false, 403);

        $branchId = (int) $branchId ?: null;

        // A rep may not price an order against a branch they have no access to.
        // The grid only ever sends a branch the form's own (already scoped)
        // picker offered, so this is the backstop for a hand-crafted call, not
        // an expected path — hence an empty catalog rather than an abort: the
        // grid degrades to "no products" instead of breaking the page.
        if ($branchId !== null && ! app(CurrentContext::class)->canAccessBranch($branchId)) {
            return ['ok' => false, 'branchId' => null, 'products' => []];
        }

        return [
            'ok' => true,
            'branchId' => $branchId,
            'products' => app(SalesOrderCatalog::class)->forBranch($branchId),
        ];
    }

    /**
     * Turns a scanned shop-printed label into a finished order line — the same
     * lookup the POS terminal uses (Pos::resolveScan()), against the same
     * service.
     *
     * A sales order records no serials, so a serial-tracked label resolves here
     * only for its product, lot and quantity: which physical unit is handed
     * over is settled when the order is invoiced, not when it is promised.
     *
     * Gated on the module's own `access` permission (mirroring
     * Pos::resolveScan()'s `pos.access` check) rather than the narrower
     * `create`/`edit` a specific page requires — a user without the module at
     * all must not be able to invoke this by calling the Livewire method
     * directly, even though Filament's page-level authorization already keeps
     * them off the create terminal and the edit form.
     *
     * @return array<string, mixed>
     */
    #[Renderless]
    public function resolveScan(string $code, ?int $branchId = null): array
    {
        abort_unless(Auth::user()?->hasPermissionTo('isms_sales_orders.access') ?? false, 403);

        if (! $branchId) {
            return ['ok' => false, 'message' => 'Select a branch first.'];
        }

        if (! app(CurrentContext::class)->canAccessBranch($branchId)) {
            return ['ok' => false, 'message' => 'You do not have access to that branch.'];
        }

        return app(BarcodeLabelService::class)->resolve($code, (int) $branchId);
    }
}
