<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpSalesOrders\Pages;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Business\Sales\Enums\SalesOrderStatus;
use App\Business\Sales\SalesOrderService;
use App\Filament\Resources\DberpReceiptOrders\DberpReceiptOrderResource;
use App\Filament\Resources\DberpSalesOrders\DberpSalesOrderResource;
use App\Filament\Resources\DberpSalesOutbounds\DberpSalesOutboundResource;
use App\Filament\Resources\Pages\EditRecord;
use App\Filament\Support\DberpPrintFilamentAction;
use App\Models\DberpSalesOrder;
use App\Services\DberpPermissionService;
use App\Support\Print\Documents\SalesOrderPrintPresenter;
use Filament\Actions\Action;
use Filament\Actions\DeleteAction;
use Filament\Forms\Components\Textarea;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

class EditDberpSalesOrder extends EditRecord
{
    protected static string $resource = DberpSalesOrderResource::class;

    /**
     * @param  array<string, mixed>  $data
     */
    protected function handleRecordUpdate(Model $record, array $data): Model
    {
        /** @var DberpSalesOrder $record */
        return app(SalesOrderService::class)->updateOrder($record, $data);
    }

    protected function getHeaderActions(): array
    {
        $canOverrideCredit = app(DberpPermissionService::class)->allows(Auth::user(), DberpPermissionService::OVERRIDE_CUSTOMER_CREDIT);

        $permissionService = app(DberpPermissionService::class);

        return [
            DberpPrintFilamentAction::forDocument(
                SalesOrderPrintPresenter::DOCUMENT_KEY,
                fn (DberpSalesOrder $record): bool => DberpSalesOrderResource::canView($record),
            ),
            Action::make('register_receipt')
                ->label(__('dberp.actions.register_receipt'))
                ->visible(fn (DberpSalesOrder $record): bool => $permissionService->allows(Auth::user(), DberpPermissionService::CREATE_RECEIPT_ORDER)
                    && DberpReceiptOrderResource::canCreate()
                    && ! in_array($record->status, [
                        SalesOrderStatus::Draft->value,
                        SalesOrderStatus::Voided->value,
                    ], true))
                ->url(fn (DberpSalesOrder $record): string => DberpReceiptOrderResource::getUrl('create', [
                    'sales_order_id' => $record->getKey(),
                    'customer_id' => $record->customer_id,
                ])),
            Action::make('create_outbound')
                ->label(__('dberp.actions.create_sales_outbound'))
                ->visible(fn (DberpSalesOrder $record): bool => in_array($record->status, [
                    SalesOrderStatus::Confirmed->value,
                    SalesOrderStatus::PartiallyShipped->value,
                ], true))
                ->url(fn (): string => DberpSalesOutboundResource::getUrl('create', ['sales_order_id' => $this->record->getKey()])),
            Action::make('confirm')
                ->label(__('dberp.actions.confirm'))
                ->formWrapper(false)
                ->form($canOverrideCredit ? [
                    Textarea::make('credit_override_reason')
                        ->label(__('dberp.fields.credit_override_reason'))
                        ->rows(3)
                        ->helperText(__('dberp.hints.sales_credit_override_reason')),
                ] : [])
                ->requiresConfirmation()
                ->modalDescription(__('dberp.hints.sales_confirm'))
                ->visible(fn (DberpSalesOrder $record): bool => $record->status === SalesOrderStatus::Draft->value)
                ->action(function (array $data) use ($canOverrideCredit): void {
                    try {
                        app(SalesOrderService::class)->confirm(
                            $this->record,
                            allowOverride: $canOverrideCredit,
                            overrideReason: $data['credit_override_reason'] ?? null,
                        );

                        $this->record->refresh();
                        $this->fillForm();

                        Notification::make()
                            ->title((string) __('dberp.notifications.confirmed'))
                            ->body((string) __('dberp.notifications.sales_order_confirmed'))
                            ->success()
                            ->send();
                    } catch (ValidationException $exception) {
                        Notification::make()
                            ->title((string) __('dberp.notifications.warning'))
                            ->body(collect($exception->errors())->flatten()->first())
                            ->danger()
                            ->send();

                        throw $exception;
                    }
                }),
            Action::make('close')
                ->label(__('dberp.actions.close'))
                ->formWrapper(false)
                ->requiresConfirmation()
                ->modalDescription(__('dberp.hints.sales_close'))
                ->visible(fn (DberpSalesOrder $record): bool => in_array($record->status, [
                    SalesOrderStatus::Confirmed->value,
                    SalesOrderStatus::PartiallyShipped->value,
                    SalesOrderStatus::FullyShipped->value,
                ], true))
                ->action(function (): void {
                    try {
                        app(SalesOrderService::class)->close($this->record);
                        $this->record->refresh();
                        $this->fillForm();

                        Notification::make()
                            ->title((string) __('dberp.notifications.confirmed'))
                            ->body((string) __('dberp.notifications.sales_order_closed'))
                            ->success()
                            ->send();
                    } catch (ValidationException $exception) {
                        Notification::make()
                            ->title((string) __('dberp.notifications.warning'))
                            ->body(collect($exception->errors())->flatten()->first())
                            ->danger()
                            ->send();

                        throw $exception;
                    }
                }),
            Action::make('void')
                ->label(__('dberp.actions.void'))
                ->requiresConfirmation()
                ->modalHeading(fn (): string => (string) __('dberp.hints.sales_order_void_heading'))
                ->modalDescription(__('dberp.hints.sales_order_void'))
                ->visible(fn (DberpSalesOrder $record): bool => in_array($record->status, [SalesOrderStatus::Draft->value, SalesOrderStatus::Confirmed->value], true))
                ->disabled(fn (DberpSalesOrder $record): bool => $record->status === SalesOrderStatus::Confirmed->value && (
                    $record->outbounds()->where('status', InventoryDocumentStatus::Effective->value)->exists()
                    || $record->returns()->where('status', InventoryDocumentStatus::Effective->value)->exists()
                ))
                ->tooltip(fn (DberpSalesOrder $record): ?string => $record->status === SalesOrderStatus::Confirmed->value && (
                    $record->outbounds()->where('status', InventoryDocumentStatus::Effective->value)->exists()
                    || $record->returns()->where('status', InventoryDocumentStatus::Effective->value)->exists()
                ) ? (string) __('dberp.hints.sales_order_void_blocked_downstream') : null)
                ->action(function (): void {
                    app(SalesOrderService::class)->void($this->record);
                    $this->record->refresh();
                    Notification::make()
                        ->title(__('dberp.notifications.sales_order_voided'))
                        ->success()
                        ->send();
                }),
            DeleteAction::make()
                ->visible(fn (DberpSalesOrder $record): bool => $record->status === SalesOrderStatus::Draft->value),
        ];
    }
}
