<?php

declare(strict_types=1);

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

namespace App\Filament\Support;

use App\Filament\Resources\DberpCustomers\DberpCustomerResource;
use App\Filament\Resources\DberpCustomerSettlementQueries\DberpCustomerSettlementQueryResource;
use App\Filament\Resources\DberpInventoryBalances\DberpInventoryBalanceResource;
use App\Filament\Resources\DberpInventoryTransactions\DberpInventoryTransactionResource;
use App\Filament\Resources\DberpProducts\DberpProductResource;
use App\Filament\Resources\DberpPurchaseOrders\DberpPurchaseOrderResource;
use App\Filament\Resources\DberpPurchaseReceipts\DberpPurchaseReceiptResource;
use App\Filament\Resources\DberpSalesOrders\DberpSalesOrderResource;
use App\Filament\Resources\DberpSalesOutbounds\DberpSalesOutboundResource;
use App\Filament\Resources\DberpSuppliers\DberpSupplierResource;
use App\Filament\Resources\DberpSupplierSettlementQueries\DberpSupplierSettlementQueryResource;
use Filament\Facades\Filament;
use Filament\Resources\Resource;
use Illuminate\Contracts\Auth\Authenticatable;
use InvalidArgumentException;
use Throwable;

/**
 * DBErp 后台预置快捷入口注册表（纯内存；工作台为静态项，「可固定」候选项合并 Filament 导航发现结果）。
 */
final class DberpShortcutRegistry
{
    /**
     * @var list<DberpShortcutItem>|null
     */
    private ?array $definitionsListCache = null;

    /** @var array<string, DberpShortcutItem>|null */
    private ?array $definitionByKeyCache = null;

    public function resetDefinitionsCache(): void
    {
        $this->definitionsListCache = null;
        $this->definitionByKeyCache = null;
    }

    public const PLACEMENT_WORKBENCH = 'workbench';

    /** 用户可固定到侧栏「常用功能」的候选项（非默认展示）。 */
    public const PLACEMENT_SIDEBAR_PINNABLE = 'sidebar_pinnable';

    /**
     * @return list<string>
     */
    public static function placements(): array
    {
        return [
            self::PLACEMENT_WORKBENCH,
            self::PLACEMENT_SIDEBAR_PINNABLE,
        ];
    }

    /**
     * @return list<string>
     */
    public function keys(): array
    {
        return array_map(
            static fn (DberpShortcutItem $item): string => $item->key,
            $this->definitions(),
        );
    }

    public function definitionByKey(string $key): ?DberpShortcutItem
    {
        return $this->definitionByKeyMap()[$key] ?? null;
    }

    /**
     * 工作台快捷区块：按指定 key 顺序输出标题与 URL（仅含含 workbench 展示位且当前用户可访问的项；未知 key 忽略）。
     *
     * @param  list<string>  $keysInDisplayOrder
     * @return list<array{title: string, url: string}>
     */
    public function shortcutViewRowsForWorkbenchKeys(array $keysInDisplayOrder, ?Authenticatable $user = null): array
    {
        $rows = [];
        foreach ($keysInDisplayOrder as $key) {
            $item = $this->definitionByKey($key);
            if ($item === null || ! $item->hasPlacement(self::PLACEMENT_WORKBENCH)) {
                continue;
            }
            if (! $item->isAccessible($user)) {
                continue;
            }
            $rows[] = [
                'title' => $item->localizedLabel(),
                'url' => $item->resolveUrl(),
            ];
        }

        return $rows;
    }

    /**
     * @return array<string, DberpShortcutItem>
     */
    private function definitionByKeyMap(): array
    {
        if ($this->definitionByKeyCache !== null) {
            return $this->definitionByKeyCache;
        }

        $map = [];
        foreach ($this->definitions() as $item) {
            $map[$item->key] = $item;
        }

        return $this->definitionByKeyCache = $map;
    }

    /**
     * @return list<DberpShortcutItem>
     */
    public function forPlacement(string $placement, ?Authenticatable $user = null): array
    {
        $items = [];
        foreach ($this->definitionsForPlacement($placement) as $item) {
            if (! $item->isAccessible($user)) {
                continue;
            }
            $items[] = $item;
        }

        usort($items, static function (DberpShortcutItem $a, DberpShortcutItem $b): int {
            if ($a->sort !== $b->sort) {
                return $a->sort <=> $b->sort;
            }

            return $a->key <=> $b->key;
        });

        return $items;
    }

    /**
     * 指定展示位下的全部项（不按用户过滤，供逐项绑定 visible 等）。
     *
     * @return list<DberpShortcutItem>
     */
    public function definitionsForPlacement(string $placement): array
    {
        $this->assertPlacement($placement);

        $items = [];
        foreach ($this->definitions() as $item) {
            if ($item->hasPlacement($placement)) {
                $items[] = $item;
            }
        }

        usort($items, static function (DberpShortcutItem $a, DberpShortcutItem $b): int {
            if ($a->sort !== $b->sort) {
                return $a->sort <=> $b->sort;
            }

            return $a->key <=> $b->key;
        });

        return $items;
    }

    private function assertPlacement(string $placement): void
    {
        if (! in_array($placement, self::placements(), true)) {
            throw new InvalidArgumentException('Unknown shortcut placement: '.$placement);
        }
    }

    /**
     * @return list<DberpShortcutItem>
     */
    private function definitions(): array
    {
        if ($this->definitionsListCache !== null) {
            return $this->definitionsListCache;
        }

        $static = $this->staticShortcutDefinitions();
        $merged = $static;

        try {
            $panel = Filament::getPanel('admin');
            $skip = $this->erpPresetResourceClasses($static);
            $dynamic = app(DberpFilamentNavigationShortcutCatalog::class)->discover($panel, $skip);
            $plugin = app(DberpPluginNavigationShortcutCatalog::class)->discover();
            $merged = [...$static, ...$dynamic, ...$plugin];
        } catch (Throwable) {
            // 控制台、安装向导或未就绪的 Filament 上下文下仅保留静态项。
        }

        return $this->definitionsListCache = $merged;
    }

    /**
     * @param  list<DberpShortcutItem>  $staticItems
     * @return list<class-string<resource>>
     */
    private function erpPresetResourceClasses(array $staticItems): array
    {
        $classes = [];
        foreach ($staticItems as $item) {
            if (! str_starts_with($item->key, 'erp.')) {
                continue;
            }
            if ($item->resourceClass !== null) {
                $classes[] = $item->resourceClass;
            }
        }

        return array_values(array_unique($classes));
    }

    /**
     * @return list<DberpShortcutItem>
     */
    private function staticShortcutDefinitions(): array
    {
        $workbenchAndPinnable = [
            self::PLACEMENT_WORKBENCH,
            self::PLACEMENT_SIDEBAR_PINNABLE,
        ];

        return [
            new DberpShortcutItem(
                key: 'erp.products',
                labelLangKey: 'dberp.shortcuts.erp.products.label',
                descriptionLangKey: 'dberp.shortcuts.erp.products.description',
                resourceClass: DberpProductResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'master_data',
                sort: 10,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.customers',
                labelLangKey: 'dberp.shortcuts.erp.customers.label',
                descriptionLangKey: 'dberp.shortcuts.erp.customers.description',
                resourceClass: DberpCustomerResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'master_data',
                sort: 20,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.suppliers',
                labelLangKey: 'dberp.shortcuts.erp.suppliers.label',
                descriptionLangKey: 'dberp.shortcuts.erp.suppliers.description',
                resourceClass: DberpSupplierResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'master_data',
                sort: 30,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.inventory_balances',
                labelLangKey: 'dberp.shortcuts.erp.inventory_balances.label',
                descriptionLangKey: 'dberp.shortcuts.erp.inventory_balances.description',
                resourceClass: DberpInventoryBalanceResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'inventory',
                sort: 40,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.inventory_transactions',
                labelLangKey: 'dberp.shortcuts.erp.inventory_transactions.label',
                descriptionLangKey: 'dberp.shortcuts.erp.inventory_transactions.description',
                resourceClass: DberpInventoryTransactionResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'inventory',
                sort: 50,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.purchase_orders',
                labelLangKey: 'dberp.shortcuts.erp.purchase_orders.label',
                descriptionLangKey: 'dberp.shortcuts.erp.purchase_orders.description',
                resourceClass: DberpPurchaseOrderResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'purchase',
                sort: 60,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.purchase_receipts',
                labelLangKey: 'dberp.shortcuts.erp.purchase_receipts.label',
                descriptionLangKey: 'dberp.shortcuts.erp.purchase_receipts.description',
                resourceClass: DberpPurchaseReceiptResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'purchase',
                sort: 70,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.sales_orders',
                labelLangKey: 'dberp.shortcuts.erp.sales_orders.label',
                descriptionLangKey: 'dberp.shortcuts.erp.sales_orders.description',
                resourceClass: DberpSalesOrderResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'sales',
                sort: 80,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.sales_outbounds',
                labelLangKey: 'dberp.shortcuts.erp.sales_outbounds.label',
                descriptionLangKey: 'dberp.shortcuts.erp.sales_outbounds.description',
                resourceClass: DberpSalesOutboundResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'sales',
                sort: 90,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.customer_settlement_query',
                labelLangKey: 'dberp.shortcuts.erp.customer_settlement_query.label',
                descriptionLangKey: 'dberp.shortcuts.erp.customer_settlement_query.description',
                resourceClass: DberpCustomerSettlementQueryResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'settlement',
                sort: 100,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
            new DberpShortcutItem(
                key: 'erp.supplier_settlement_query',
                labelLangKey: 'dberp.shortcuts.erp.supplier_settlement_query.label',
                descriptionLangKey: 'dberp.shortcuts.erp.supplier_settlement_query.description',
                resourceClass: DberpSupplierSettlementQueryResource::class,
                pageClass: null,
                permissionCodesAny: null,
                group: 'settlement',
                sort: 110,
                placements: $workbenchAndPinnable,
                openResourceCreate: false,
                usesFilamentNavigationLabel: false,
                navigationUiGroup: null,
            ),
        ];
    }
}
