<?php

declare(strict_types=1);

namespace App\Support;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Business\Inventory\Enums\TransferDocumentStatus;
use App\Business\Inventory\InventoryDocumentManualLineBulkAddService;
use App\Business\Purchase\Enums\PurchaseOrderStatus;
use App\Business\Purchase\Enums\PurchaseRequestStatus;
use App\Business\Purchase\PurchaseOrderService;
use App\Business\Purchase\PurchaseRequestService;
use App\Business\Sales\Enums\SalesOrderStatus;
use App\Business\Sales\Enums\SalesQuoteStatus;
use App\Business\Sales\SalesOrderService;
use App\Business\Sales\SalesQuoteService;
use App\Models\DberpOtherStockInOrder;
use App\Models\DberpOtherStockOutOrder;
use App\Models\DberpPurchaseOrder;
use App\Models\DberpPurchaseRequest;
use App\Models\DberpSalesOrder;
use App\Models\DberpSalesQuote;
use App\Models\DberpTransferOrder;
use Filament\Actions\Action;
use Filament\Forms\Components\Component;
use Filament\Notifications\Notification;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;

/**
 * 单据明细 RelationManager 表头「批量添加商品」。
 *
 * NOTE: 未来若支持 Excel 明细导入，仅作为录入方式；须复用商品/单位/定价/来源校验，
 * 不得绕过采购申请、询价转单、库存过账或服务层确认规则。
 */
final class DberpDocumentLineBulkProductAddHeaderActions
{
    public static function purchaseOrderItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_PURCHASABLE,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

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

                $created = app(PurchaseOrderService::class)->createManualItemsFromSkus(
                    $order,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function salesOrderItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_SALABLE,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

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

                $created = app(SalesOrderService::class)->createManualItemsFromSkus(
                    $order,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function salesQuoteItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_quote_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_SALABLE,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

                return $owner instanceof DberpSalesQuote
                    && in_array($owner->currentStatus(), [SalesQuoteStatus::Draft, SalesQuoteStatus::PendingEffective], true);
            },
            run: function (array $data) use ($resolveOwner): void {
                $quote = $resolveOwner();
                if (! $quote instanceof DberpSalesQuote) {
                    return;
                }

                $created = app(SalesQuoteService::class)->createManualItemsFromSkus(
                    $quote,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function purchaseRequestItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_request_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFieldsForPurchaseRequest(),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

                return $owner instanceof DberpPurchaseRequest
                    && in_array($owner->status, [PurchaseRequestStatus::Draft->value, PurchaseRequestStatus::Pending->value], true);
            },
            run: function (array $data) use ($resolveOwner): void {
                $request = $resolveOwner();
                if (! $request instanceof DberpPurchaseRequest) {
                    return;
                }

                $created = app(PurchaseRequestService::class)->createManualItemsFromSkus(
                    $request,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (int) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_WAREHOUSE_ID] ?? 0),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function otherStockInOrderItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_inventory_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_INVENTORY,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

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

                $created = app(InventoryDocumentManualLineBulkAddService::class)->createOtherStockInItemsFromSkus(
                    $order,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function otherStockOutOrderItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_inventory_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_INVENTORY,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

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

                $created = app(InventoryDocumentManualLineBulkAddService::class)->createOtherStockOutItemsFromSkus(
                    $order,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    public static function transferOrderItems(callable $resolveOwner): Action
    {
        return self::makeBulkAddAction(
            resolveOwner: $resolveOwner,
            modalDescription: __('dberp.hints.bulk_add_document_line_products_inventory_modal'),
            formFields: DberpDocumentLineBulkProductAddFormFields::modalFields(
                DberpProductSkuSelectOptions::PRODUCT_SCOPE_INVENTORY,
            ),
            visible: function () use ($resolveOwner): bool {
                $owner = $resolveOwner();

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

                $created = app(InventoryDocumentManualLineBulkAddService::class)->createTransferItemsFromSkus(
                    $order,
                    DberpDocumentLineBulkProductAddFormFields::normalizeSkuIds($data[DberpDocumentLineBulkProductAddFormFields::FIELD_PRODUCT_SKU_IDS] ?? []),
                    (string) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_DEFAULT_QUANTITY] ?? '1'),
                    filled($data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK] ?? null)
                        ? (string) $data[DberpDocumentLineBulkProductAddFormFields::FIELD_REMARK]
                        : null,
                    (bool) ($data[DberpDocumentLineBulkProductAddFormFields::FIELD_SKIP_EXISTING_SKUS] ?? false),
                );

                self::notifyBulkAddResult($created);
            },
        );
    }

    /**
     * @param  list<Component>  $formFields
     */
    private static function makeBulkAddAction(
        callable $resolveOwner,
        string|Htmlable|null $modalDescription,
        array $formFields,
        callable $visible,
        callable $run,
    ): Action {
        return Action::make('bulk_add_products')
            ->label(__('dberp.actions.bulk_add_document_line_products'))
            ->modalHeading(__('dberp.actions.bulk_add_document_line_products'))
            ->modalDescription($modalDescription)
            ->visible($visible)
            ->form($formFields)
            ->action($run);
    }

    /**
     * @param  list<Model>  $created
     */
    private static function notifyBulkAddResult(array $created): void
    {
        $count = count($created);

        if ($count === 0) {
            Notification::make()
                ->title((string) __('dberp.notifications.bulk_add_document_line_products_none'))
                ->warning()
                ->send();

            return;
        }

        Notification::make()
            ->title((string) __('dberp.notifications.bulk_add_document_line_products_success', ['count' => $count]))
            ->success()
            ->send();
    }
}
