<?php

declare(strict_types=1);

namespace App\Filament\Widgets;

use App\Business\Inventory\InventoryGovernanceReminderService;
use App\Filament\Resources\DberpAuditLogs\DberpAuditLogResource;
use App\Filament\Resources\DberpInventoryBatches\DberpInventoryBatchResource;
use App\Filament\Resources\DberpInventoryExceptions\DberpInventoryExceptionResource;
use App\Filament\Resources\DberpInventoryReplenishmentSuggestions\DberpInventoryReplenishmentSuggestionResource;
use App\Filament\Resources\DberpInventoryRules\DberpInventoryRuleResource;
use App\Filament\Resources\DberpInventorySerialNumbers\DberpInventorySerialNumberResource;
use App\Filament\Resources\DberpInventoryWarnings\DberpInventoryWarningResource;
use App\Filament\Resources\DberpStocktakeDifferences\DberpStocktakeDifferenceResource;
use App\Filament\Support\DberpShortcutRegistry;
use App\Services\DberpPermissionService;
use Filament\Widgets\Widget;
use Illuminate\Support\Facades\Auth;

class InventoryGovernanceWorkbenchLinksWidget extends Widget
{
    protected static bool $isLazy = true;

    protected string $view = 'filament.widgets.inventory-governance-workbench-links-widget';

    protected int|string|array $columnSpan = 'full';

    public static function canView(): bool
    {
        return app(DberpPermissionService::class)->allows(Auth::user(), DberpPermissionService::VIEW_WORKBENCH_OVERVIEW);
    }

    /**
     * @return list<array<string, string|int>>
     */
    public function reminderItems(): array
    {
        $items = app(InventoryGovernanceReminderService::class)->reminderItems();

        return array_values(array_filter(array_map(function (array $item): array {
            $item['url'] = $this->urlForReminderKey((string) $item['key']);

            return $item;
        }, $items), fn (array $item): bool => $this->canAccessInventoryReminderKey((string) $item['key'])));
    }

    /**
     * @return list<array<string, string>>
     */
    public function shortcutLinks(): array
    {
        $links = app(DberpShortcutRegistry::class)->shortcutViewRowsForWorkbenchKeys(
            ['erp.inventory_balances', 'erp.inventory_transactions'],
            Auth::user(),
        );

        if (DberpInventoryBatchResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_batches'), 'url' => DberpInventoryBatchResource::getUrl('index')];
        }
        if (DberpInventorySerialNumberResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_serial'), 'url' => DberpInventorySerialNumberResource::getUrl('index')];
        }
        if (DberpStocktakeDifferenceResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_differences'), 'url' => DberpStocktakeDifferenceResource::getUrl('index')];
        }
        if (DberpInventoryReplenishmentSuggestionResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_replenishment'), 'url' => DberpInventoryReplenishmentSuggestionResource::getUrl('index')];
        }
        if (DberpInventoryWarningResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_warnings'), 'url' => DberpInventoryWarningResource::getUrl('index')];
        }
        if (DberpInventoryRuleResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_rules'), 'url' => DberpInventoryRuleResource::getUrl('index')];
        }
        if (DberpInventoryExceptionResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_exceptions'), 'url' => $this->exceptionUrl()];
        }

        if (DberpAuditLogResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.shortcut_audit'), 'url' => $this->auditUrl('dberp.inventory_')];
        }

        return $links;
    }

    /**
     * @return list<array<string, string>>
     */
    public function exceptionLinks(): array
    {
        $links = [];

        if (DberpInventoryExceptionResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.exceptions_expired_batch_stock'), 'url' => $this->exceptionUrl('expired_batch_stock')];
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.exceptions_disabled_batch_stock'), 'url' => $this->exceptionUrl('disabled_batch_stock')];
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.exceptions_serial_batch_mismatch'), 'url' => $this->exceptionUrl('serial_batch_mismatch')];
        }
        if (DberpStocktakeDifferenceResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.exceptions_pending_difference'), 'url' => $this->differenceUrl('pending')];
        }
        if (DberpInventoryReplenishmentSuggestionResource::canViewAny()) {
            $links[] = ['title' => (string) __('dberp.widgets.inventory_workbench.exceptions_pending_replenishment'), 'url' => $this->replenishmentUrl('pending')];
        }

        return $links;
    }

    /**
     * 与 urlForReminderKey 目标一致：无权限的提醒不展示，避免点击进入 403。
     */
    private function canAccessInventoryReminderKey(string $key): bool
    {
        return match ($key) {
            'expired_batch' => DberpInventoryExceptionResource::canViewAny(),
            'near_expiry_batch' => DberpInventoryBatchResource::canViewAny(),
            'low_stock' => DberpInventoryWarningResource::canViewAny(),
            'pending_replenishment' => DberpInventoryReplenishmentSuggestionResource::canViewAny(),
            'pending_stocktake_difference' => DberpStocktakeDifferenceResource::canViewAny(),
            'serial_mismatch' => DberpInventoryExceptionResource::canViewAny(),
            'open_inventory_exception' => DberpInventoryExceptionResource::canViewAny(),
            default => DberpInventoryExceptionResource::canViewAny(),
        };
    }

    private function urlForReminderKey(string $key): string
    {
        return match ($key) {
            'expired_batch' => $this->exceptionUrl('expired_batch_stock'),
            'near_expiry_batch' => DberpInventoryBatchResource::getUrl('index').'?'.http_build_query([
                'filters' => [
                    'expiry_status' => [
                        'value' => 'near_expiry',
                    ],
                ],
            ]),
            'low_stock' => DberpInventoryWarningResource::getUrl('index'),
            'pending_replenishment' => $this->replenishmentUrl('pending'),
            'pending_stocktake_difference' => $this->differenceUrl('pending'),
            'serial_mismatch' => $this->exceptionUrl('serial_batch_mismatch'),
            'open_inventory_exception' => $this->exceptionUrl(),
            default => $this->exceptionUrl(),
        };
    }

    private function differenceUrl(string $status): string
    {
        return DberpStocktakeDifferenceResource::getUrl('index').'?'.http_build_query([
            'filters' => [
                'status' => [
                    'value' => $status,
                ],
            ],
        ]);
    }

    private function replenishmentUrl(string $status): string
    {
        return DberpInventoryReplenishmentSuggestionResource::getUrl('index').'?'.http_build_query([
            'filters' => [
                'status' => [
                    'value' => $status,
                ],
            ],
        ]);
    }

    private function exceptionUrl(?string $type = null): string
    {
        $filters = [
            'status' => [
                'value' => 'open',
            ],
        ];

        if ($type !== null) {
            $filters['exception_type'] = [
                'value' => $type,
            ];
        }

        return DberpInventoryExceptionResource::getUrl('index').'?'.http_build_query([
            'filters' => $filters,
        ]);
    }

    private function auditUrl(string $keyword): string
    {
        return DberpAuditLogResource::getUrl('index').'?'.http_build_query([
            'filters' => [
                'action' => [
                    'value' => $keyword,
                ],
            ],
        ]);
    }
}
