<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Filament\Resources\DberpPurchaseOrders\Concerns;

use App\Business\Purchase\Enums\PurchaseOrderSourceMode;
use App\Business\Purchase\Enums\PurchaseRequestStatus;
use App\Business\Purchase\PurchaseSourceDocumentService;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpEmployee;
use App\Models\DberpPurchaseInquiryQuote;
use App\Models\DberpPurchaseRequest;
use App\Models\DberpPurchaseRequestItem;
use App\Models\DberpSupplier;
use App\Support\DberpDocumentLineSpecPresentation;
use App\Support\DberpNumberFormatter;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Database\Eloquent\Builder;

trait ProvidesDberpPurchaseOrderCreationFormFields
{
    /**
     * @return list<Component|\Filament\Schemas\Components\Component>
     */
    protected function purchaseOrderCreationFormSections(): array
    {
        return [
            Section::make(__('dberp.sections.purchase_order_source'))
                ->schema([
                    Select::make('source_mode')
                        ->label(__('dberp.fields.purchase_order_source_mode'))
                        ->options(PurchaseOrderSourceMode::options())
                        ->default(PurchaseOrderSourceMode::Manual->value)
                        ->live()
                        ->required(),
                ]),
            Section::make(__('dberp.sections.purchase_document'))
                ->schema([
                    Select::make('supplier_id')
                        ->label(__('dberp.fields.supplier'))
                        ->options(fn (): array => DberpSupplier::query()->where('is_enabled', true)->orderBy('sort_order')->orderBy('id')->pluck('name', 'id')->all())
                        ->searchable()
                        ->preload()
                        ->required(fn (Get $get): bool => in_array($get('source_mode'), [
                            PurchaseOrderSourceMode::Manual->value,
                            PurchaseOrderSourceMode::PurchaseRequest->value,
                        ], true))
                        ->disabled(fn (Get $get): bool => $get('source_mode') === PurchaseOrderSourceMode::InquiryQuote->value),
                    Select::make('handler_employee_id')
                        ->label(__('dberp.fields.handler_employee'))
                        ->options(fn (): array => DberpEmployee::selectOptionsForFilament(fn (Builder $q) => $q->where('is_enabled', true)))
                        ->searchable()
                        ->preload(),
                    DateTimePicker::make('business_time')
                        ->label(__('dberp.fields.business_time'))
                        ->default(fn () => now())
                        ->seconds(false)
                        ->required(),
                    Textarea::make('remark')
                        ->label(__('dberp.fields.remark'))
                        ->rows(2)
                        ->columnSpanFull(),
                ])
                ->columns(3),
            Section::make(__('dberp.sections.purchase_order_from_request'))
                ->visible(fn (Get $get): bool => $get('source_mode') === PurchaseOrderSourceMode::PurchaseRequest->value)
                ->schema([
                    Select::make('purchase_request_id')
                        ->label(__('dberp.fields.purchase_request'))
                        ->options(fn (): array => $this->selectablePurchaseRequestOptionsForOrder())
                        ->searchable()
                        ->preload()
                        ->live()
                        ->afterStateUpdated(fn (Set $set, ?int $state): mixed => $set('request_lines', $this->buildRequestLinesForPurchaseOrder($state)))
                        ->required(),
                    Repeater::make('request_lines')
                        ->label(__('dberp.sections.purchase_request_line_selection'))
                        ->columnSpanFull()
                        ->addable(false)
                        ->deletable(false)
                        ->reorderable(false)
                        ->schema([
                            Hidden::make('purchase_request_item_id'),
                            TextInput::make('product_label')
                                ->label(__('dberp.fields.product'))
                                ->disabled()
                                ->dehydrated(false),
                            TextInput::make('remaining_quantity')
                                ->label(__('dberp.fields.remaining_quantity'))
                                ->disabled()
                                ->dehydrated(false)
                                ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                            DberpFilamentNumberFields::documentLineQuantityInput(
                                TextInput::make('source_quantity')
                                    ->label(__('dberp.fields.source_quantity'))
                                    ->required(),
                            ),
                        ])
                        ->columns(3),
                ]),
            Section::make(__('dberp.sections.purchase_order_from_inquiry_quote'))
                ->visible(fn (Get $get): bool => $get('source_mode') === PurchaseOrderSourceMode::InquiryQuote->value)
                ->schema([
                    Select::make('quote_prefill_supplier_id')
                        ->label(__('dberp.fields.supplier'))
                        ->options(fn (): array => DberpSupplier::query()->where('is_enabled', true)->orderBy('sort_order')->orderBy('id')->pluck('name', 'id')->all())
                        ->searchable()
                        ->preload()
                        ->live()
                        ->afterStateUpdated(function (Set $set, Get $get, ?int $state): void {
                            $set('quote_lines', $this->buildQuoteLinesForPurchaseOrder($state, $get('purchase_request_id')));
                            $set('supplier_id', $state);
                        }),
                    Select::make('purchase_request_id')
                        ->label(__('dberp.fields.purchase_request'))
                        ->options(fn (): array => $this->selectablePurchaseRequestOptionsForOrder())
                        ->searchable()
                        ->preload()
                        ->live()
                        ->afterStateUpdated(fn (Set $set, Get $get, ?int $state): mixed => $set(
                            'quote_lines',
                            $this->buildQuoteLinesForPurchaseOrder($get('quote_prefill_supplier_id'), $state),
                        )),
                    Repeater::make('quote_lines')
                        ->label(__('dberp.sections.purchase_inquiry_quote_selection'))
                        ->columnSpanFull()
                        ->addable(false)
                        ->deletable(false)
                        ->reorderable(false)
                        ->schema([
                            Hidden::make('purchase_inquiry_quote_id'),
                            TextInput::make('quote_label')
                                ->label(__('dberp.fields.selectable_inquiry_quote'))
                                ->disabled()
                                ->dehydrated(false),
                            TextInput::make('remaining_quantity')
                                ->label(__('dberp.fields.remaining_quantity'))
                                ->disabled()
                                ->dehydrated(false)
                                ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                            DberpFilamentNumberFields::documentLineQuantityInput(
                                TextInput::make('source_quantity')
                                    ->label(__('dberp.fields.source_quantity'))
                                    ->required(),
                            ),
                        ])
                        ->columns(3),
                ]),
        ];
    }

    /**
     * @return list<array<string, mixed>>
     */
    protected function buildRequestLinesForPurchaseOrder(?int $purchaseRequestId): array
    {
        if ($purchaseRequestId === null || $purchaseRequestId <= 0) {
            return [];
        }

        $request = DberpPurchaseRequest::query()
            ->with(['items.product', 'items.productSku'])
            ->find($purchaseRequestId);

        if ($request === null) {
            return [];
        }

        return $request->items
            ->filter(fn (DberpPurchaseRequestItem $item): bool => (float) $item->remaining_quantity > 0.00005)
            ->map(fn (DberpPurchaseRequestItem $item): array => [
                'purchase_request_item_id' => $item->getKey(),
                'product_label' => $this->formatPurchaseRequestItemLabelForOrder($item),
                'remaining_quantity' => $item->remaining_quantity,
                'source_quantity' => $item->remaining_quantity,
            ])
            ->values()
            ->all();
    }

    /**
     * @return list<array<string, mixed>>
     */
    protected function buildQuoteLinesForPurchaseOrder(?int $supplierId, mixed $purchaseRequestId = null): array
    {
        if ($supplierId === null || $supplierId <= 0) {
            return [];
        }

        $sourceDocumentService = app(PurchaseSourceDocumentService::class);

        $filters = ['supplier_id' => $supplierId];

        if ($purchaseRequestId) {
            $filters['purchase_request_id'] = (int) $purchaseRequestId;
        }

        return $sourceDocumentService
            ->selectableInquiryQuotesForConversionQuery($filters)
            ->with(['supplier', 'purchaseRequestItem'])
            ->orderBy('quote_date')
            ->orderBy('id')
            ->get()
            ->map(function (DberpPurchaseInquiryQuote $quote) use ($sourceDocumentService): array {
                $requestItem = $quote->purchaseRequestItem;

                if ($requestItem === null) {
                    return [];
                }

                $remaining = $sourceDocumentService->calculatePurchaseRequestItemRemainingQuantity($requestItem);

                return [
                    'purchase_inquiry_quote_id' => $quote->getKey(),
                    'quote_label' => trim($quote->code.' / '.($quote->supplier_name_snapshot ?? '-').' / '.DberpNumberFormatter::price($quote->unit_price)),
                    'remaining_quantity' => $remaining,
                    'source_quantity' => $remaining,
                ];
            })
            ->filter(static fn (array $row): bool => $row !== [])
            ->values()
            ->all();
    }

    /**
     * @return array<int, string>
     */
    protected function selectablePurchaseRequestOptionsForOrder(): array
    {
        return DberpPurchaseRequest::query()
            ->whereIn('status', [
                PurchaseRequestStatus::Pending->value,
                PurchaseRequestStatus::PartiallyConverted->value,
            ])
            ->where('remaining_quantity', '>', 0)
            ->orderByDesc('request_time')
            ->pluck('code', 'id')
            ->all();
    }

    protected function formatPurchaseRequestItemLabelForOrder(DberpPurchaseRequestItem $item): string
    {
        $item->loadMissing(DberpDocumentLineSpecPresentation::eagerLoadsForDocumentLines(['product', 'productSku']));

        $name = $item->product?->name ?? (string) __('dberp.fields.product').' #'.$item->product_id;
        $spec = DberpDocumentLineSpecPresentation::lineSpecSummary($item);

        return $spec !== '' ? $name.' · '.$spec : $name;
    }
}
