<?php

declare(strict_types=1);

namespace App\Support;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Business\Inventory\InventoryDocumentLineBarcodeQuickAddService;
use App\Business\Sales\Enums\SalesOrderStatus;
use App\Business\Sales\SalesOrderService;
use App\Models\DberpOtherStockOutOrder;
use App\Models\DberpSalesOrder;
use App\Models\DberpStocktakeOrder;
use Filament\Actions\Action;
use Illuminate\Validation\ValidationException;

/**
 * 单据明细 RelationManager 表头「条码快录」。
 *
 * NOTE: 不得用于必须绑定上游订单行的单据（采购到货、销售出库等）。
 * 未来 Excel 明细导入亦不得绕过本类单据的来源、单位与库存校验。
 */
final class DberpDocumentLineBarcodeQuickAddHeaderActions
{
    public static function salesOrderItems(callable $resolveOwner): Action
    {
        return self::makeAction(
            name: 'barcode_quick_add',
            resolveOwner: $resolveOwner,
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

                return $owner instanceof DberpSalesOrder
                    && $owner->status === SalesOrderStatus::Draft->value;
            },
            action: function (array $data) use ($resolveOwner): void {
                $order = $resolveOwner();
                if (! $order instanceof DberpSalesOrder) {
                    return;
                }

                self::runQuickAdd(
                    fn () => app(SalesOrderService::class)->quickAddItemByBarcode($order, $data),
                );
            },
            modalDescription: __('dberp.hints.barcode_quick_add_sales_order_modal'),
        );
    }

    public static function stocktakeOrderItems(callable $resolveOwner): Action
    {
        return self::makeAction(
            name: 'barcode_quick_add',
            resolveOwner: $resolveOwner,
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

                return $owner instanceof DberpStocktakeOrder
                    && $owner->status === InventoryDocumentStatus::Draft->value;
            },
            action: function (array $data) use ($resolveOwner): void {
                $order = $resolveOwner();
                if (! $order instanceof DberpStocktakeOrder) {
                    return;
                }

                self::runQuickAdd(
                    fn () => app(InventoryDocumentLineBarcodeQuickAddService::class)->quickAddStocktakeLine($order, $data),
                );
            },
            modalDescription: __('dberp.hints.barcode_quick_add_stocktake_modal'),
        );
    }

    public static function otherStockOutOrderItems(callable $resolveOwner): Action
    {
        return self::makeAction(
            name: 'barcode_quick_add',
            resolveOwner: $resolveOwner,
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

                return $owner instanceof DberpOtherStockOutOrder
                    && $owner->status === InventoryDocumentStatus::Draft->value;
            },
            action: function (array $data) use ($resolveOwner): void {
                $order = $resolveOwner();
                if (! $order instanceof DberpOtherStockOutOrder) {
                    return;
                }

                self::runQuickAdd(
                    fn () => app(InventoryDocumentLineBarcodeQuickAddService::class)->quickAddOtherStockOutLine($order, $data),
                );
            },
            modalDescription: __('dberp.hints.barcode_quick_add_other_stock_out_modal'),
        );
    }

    private static function makeAction(
        string $name,
        callable $resolveOwner,
        callable $visible,
        callable $action,
        string $modalDescription,
    ): Action {
        return Action::make($name)
            ->label(__('dberp.actions.barcode_quick_add_document_line'))
            ->modalHeading(__('dberp.actions.barcode_quick_add_document_line'))
            ->modalDescription($modalDescription)
            ->visible($visible)
            ->form(DberpDocumentLineBarcodeQuickAddFormFields::modalFields())
            ->action(function (array $data) use ($action): void {
                $action($data);
            });
    }

    /**
     * @param  callable(): string  $quickAdd
     */
    private static function runQuickAdd(callable $quickAdd): void
    {
        try {
            $outcome = $quickAdd();
            DberpDocumentLineBarcodeQuickAddSupport::notifyOutcome($outcome);
        } catch (ValidationException $exception) {
            DberpDocumentLineBarcodeQuickAddSupport::notifyValidation($exception);

            throw $exception;
        }
    }
}
