<?php

declare(strict_types=1);

namespace App\Support;

class TokenAbilities
{
    public const WILDCARD = '*';

    /**
     * Catalog of all valid abilities grouped for UI presentation.
     * @return array<string, array<int, array{key: string, label: string}>>
     */
    public static function catalog(): array
    {
        return [
            'Identity' => self::group([
                'users:read', 'users:write', 'users:delete', 'users:impersonate',
                'chapters:read', 'chapters:write', 'chapters:delete',
                'chapter-members:read', 'chapter-members:write', 'chapter-members:delete',
                'announcements:read', 'announcements:write', 'announcements:delete',
            ]),
            'Content' => self::group([
                'pages:read', 'pages:write', 'pages:delete',
                'landing-pages:read', 'landing-pages:write', 'landing-pages:delete',
                'page-memory:read', 'page-memory:write',
            ]),
            'Files' => self::group([
                'files:read', 'files:upload', 'files:delete', 'files:publish',
            ]),
            'System' => self::group([
                'system-settings:read', 'system-settings:write',
                'db-backups:read', 'db-backups:write', 'db-backups:restore',
                'table-logs:read',
                'global-transactions:read', 'global-transactions:write',
            ]),
            'Accounting' => self::group([
                'accounts:read', 'accounts:write', 'accounts:delete',
                'account-transactions:read', 'account-transactions:write', 'account-transactions:void',
                'member-ledgers:read', 'member-ledgers:write',
            ]),
            'Cooperatives' => self::group([
                'cooperatives:read', 'cooperatives:write', 'cooperatives:delete',
                'cooperative-members:read', 'cooperative-members:write', 'cooperative-members:delete',
                'cooperative-documents:read', 'cooperative-documents:write', 'cooperative-documents:delete',
                'cooperative-resolutions:read', 'cooperative-resolutions:write', 'cooperative-resolutions:delete',
                'cooperative-votes:read', 'cooperative-votes:write',
                'main-organization:read', 'main-organization:write',
            ]),
            'Market' => self::group([
                'products:read', 'products:write', 'products:delete',
                'product-transactions:read', 'product-transactions:write', 'product-transactions:void',
                'stores:read', 'stores:write', 'stores:delete',
                'store-managers:read', 'store-managers:write',
                'customers:read', 'customers:write', 'customers:delete',
                'farmers:read', 'farmers:write', 'farmers:delete',
                'couriers:read', 'couriers:write',
                'shipments:read', 'shipments:write',
                'carts:read', 'carts:write',
            ]),
            'POS' => self::group([
                'pos-sessions:read', 'pos-sessions:write', 'pos-sessions:close',
                'pos-transactions:read', 'pos-transactions:write', 'pos-transactions:void',
                'pos-access-keys:read', 'pos-access-keys:write', 'pos-access-keys:delete',
            ]),
            'Property' => self::group([
                'properties:read', 'properties:write', 'properties:delete',
                'referrals:read', 'referrals:write',
                'referral-keys:read', 'referral-keys:write', 'referral-keys:delete',
            ]),
        ];
    }

    /** @return array<int, string> */
    public static function all(): array
    {
        $out = [];
        foreach (self::catalog() as $group) {
            foreach ($group as $entry) {
                $out[] = $entry['key'];
            }
        }
        return $out;
    }

    public static function exists(string $ability): bool
    {
        return $ability === self::WILDCARD || in_array($ability, self::all(), true);
    }

    /**
     * @param array<int, string> $keys
     * @return array<int, array{key: string, label: string}>
     */
    private static function group(array $keys): array
    {
        return array_map(static fn ($k) => ['key' => $k, 'label' => $k], $keys);
    }
}
