<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpPurchaseInquiries\Concerns;

use App\Business\Purchase\Enums\PurchaseInquiryStatus;
use App\Business\Purchase\PurchaseInquiryConversionService;
use App\Business\Purchase\PurchaseSourceDocumentService;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpEmployee;
use App\Models\DberpPurchaseInquiry;
use App\Models\DberpPurchaseInquiryQuote;
use App\Services\DberpPermissionService;
use App\Support\DberpNumberFormatter;
use Filament\Actions\Action;
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\Notifications\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;

trait ProvidesDberpPurchaseInquiryCollaborationHeaderActions
{
    /**
     * @return list<Action>
     */
    protected function purchaseInquiryCollaborationHeaderActions(): array
    {
        return [
            $this->makeConvertInquiryQuotesToPurchaseOrderAction(),
        ];
    }

    protected function makeConvertInquiryQuotesToPurchaseOrderAction(): Action
    {
        return Action::make('convert_inquiry_quotes_to_purchase_order')
            ->label(__('dberp.actions.convert_inquiry_quotes_to_purchase_order'))
            ->modalHeading(__('dberp.actions.convert_inquiry_quotes_to_purchase_order'))
            ->modalDescription(__('dberp.hints.purchase_inquiry_convert_quotes'))
            ->visible(fn (DberpPurchaseInquiry $record): bool => app(DberpPermissionService::class)->allows(Auth::user(), DberpPermissionService::CONVERT_PURCHASE_REQUEST)
                && $record->status === PurchaseInquiryStatus::Open->value
                && $this->inquiryHasConvertibleQuotes($record))
            ->fillForm(fn (DberpPurchaseInquiry $record): array => $this->buildInquiryQuoteSelectionFormDefaults($record))
            ->form($this->inquiryQuoteConversionFormSchema())
            ->action(function (array $data): void {
                $inquiry = $this->getPurchaseInquiryCollaborationRecord();

                $orders = app(PurchaseInquiryConversionService::class)->convertQuotesToPurchaseOrders(
                    inquiry: $inquiry,
                    quoteQuantities: $this->extractQuoteQuantitiesFromForm($data),
                    handlerEmployeeId: ($data['handler_employee_id'] ?? null) ? (int) $data['handler_employee_id'] : null,
                    businessTime: $data['business_time'] ?? now(),
                    remark: $data['remark'] ?? null,
                );

                $this->refreshPurchaseInquiryCollaborationRecord();

                $body = count($orders) === 1
                    ? (string) __('dberp.messages.purchase_inquiry_quote_convert_success', ['code' => $orders[0]->code])
                    : (string) __('dberp.messages.purchase_inquiry_quote_convert_success_multiple', [
                        'count' => count($orders),
                        'codes' => collect($orders)->pluck('code')->implode('、'),
                    ]);

                Notification::make()
                    ->title((string) __('dberp.notifications.saved'))
                    ->body($body)
                    ->success()
                    ->send();
            });
    }

    /**
     * @return list<Component|\Filament\Schemas\Components\Component>
     */
    protected function inquiryQuoteConversionFormSchema(): array
    {
        return [
            Repeater::make('quotes')
                ->label(__('dberp.sections.purchase_inquiry_quote_selection'))
                ->columnSpanFull()
                ->addable(false)
                ->deletable(false)
                ->reorderable(false)
                ->defaultItems(0)
                ->schema([
                    Hidden::make('purchase_inquiry_quote_id'),
                    TextInput::make('quote_label')
                        ->label(__('dberp.fields.purchase_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('convert_quantity')
                            ->label(__('dberp.fields.convert_quantity'))
                            ->required(),
                    ),
                ])
                ->columns(3),
            Select::make('handler_employee_id')
                ->label(__('dberp.fields.handler_employee'))
                ->options(fn (): array => DberpEmployee::selectOptionsForFilament(fn (Builder $q) => $q->where('is_enabled', true)))
                ->default(fn (): ?int => $this->getPurchaseInquiryCollaborationRecord()->handler_employee_id)
                ->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(3),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    protected function buildInquiryQuoteSelectionFormDefaults(DberpPurchaseInquiry $inquiry): array
    {
        $sourceDocumentService = app(PurchaseSourceDocumentService::class);

        $quotes = $sourceDocumentService
            ->selectableInquiryQuotesForConversionQuery([
                'purchase_inquiry_id' => $inquiry->getKey(),
            ])
            ->with(['supplier', 'purchaseRequestItem', 'purchaseInquiryItem.product'])
            ->orderBy('supplier_id')
            ->orderBy('id')
            ->get();

        return [
            'quotes' => $quotes->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 ?? $quote->supplier?->name ?? '-').' / '.DberpNumberFormatter::price($quote->unit_price)),
                    'remaining_quantity' => $remaining,
                    'convert_quantity' => $remaining,
                ];
            })->filter(static fn (array $row): bool => $row !== [])->values()->all(),
        ];
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<int, float>
     */
    protected function extractQuoteQuantitiesFromForm(array $data): array
    {
        $quantities = [];

        foreach ((array) ($data['quotes'] ?? []) as $line) {
            if (! is_array($line)) {
                continue;
            }

            $quoteId = (int) ($line['purchase_inquiry_quote_id'] ?? 0);
            $quantity = (float) ($line['convert_quantity'] ?? 0);

            if ($quoteId <= 0 || $quantity <= 0) {
                continue;
            }

            $quantities[$quoteId] = $quantity;
        }

        return $quantities;
    }

    protected function inquiryHasConvertibleQuotes(DberpPurchaseInquiry $inquiry): bool
    {
        return app(PurchaseSourceDocumentService::class)
            ->selectableInquiryQuotesForConversionQuery([
                'purchase_inquiry_id' => $inquiry->getKey(),
            ])
            ->exists();
    }

    abstract protected function getPurchaseInquiryCollaborationRecord(): DberpPurchaseInquiry;

    protected function refreshPurchaseInquiryCollaborationRecord(): void
    {
        $this->getPurchaseInquiryCollaborationRecord()->refresh();
    }
}
