<?php

namespace classes;

use modules\subusers\helpers\subusers_permission_node_key;

class subuser_permission_templates_service
{
    public const TEMPLATE_DEACTIVATED = 'deactivated';
    public const TEMPLATE_DRIVER = 'driver';
    public const TEMPLATE_BOOKING_COORDINATOR = 'booking_coordinator';
    public const TEMPLATE_FLEET_ADMIN = 'fleet_admin';
    public const TEMPLATE_CUSTOM = 'custom';

    /**
     * @var array<string, array{label:string,description:string,enabled:bool,permissions:array<int,string>}>
     */
    private const TEMPLATES = [
        self::TEMPLATE_DEACTIVATED => [
            'label' => 'Deactivated',
            'description' => 'Keeps the driver linked to the customer without active access.',
            'enabled' => false,
            'permissions' => [],
        ],
        self::TEMPLATE_DRIVER => [
            'label' => 'Driver',
            'description' => 'Can use self-service, manage own bookings, see vehicles, and view orders.',
            'enabled' => true,
            'permissions' => [
                'VEHICLES_LIST',
                'SELFSERVE_LIST',
                'SELFSERVE_ADD',
                'BOOKINGS_LIST',
                'BOOKINGS_ADD',
                'ORDERS_LIST',
            ],
        ],
        self::TEMPLATE_BOOKING_COORDINATOR => [
            'label' => 'Booking coordinator',
            'description' => 'Can coordinate bookings and see the related vehicles and orders.',
            'enabled' => true,
            'permissions' => [
                'VEHICLES_LIST',
                'BOOKINGS_LIST',
                'BOOKINGS_ADD',
                'BOOKINGS_EDIT',
                'ORDERS_LIST',
            ],
        ],
        self::TEMPLATE_FLEET_ADMIN => [
            'label' => 'Fleet admin',
            'description' => 'Can manage drivers, vehicles, bookings, self-service, and orders for the customer.',
            'enabled' => true,
            'permissions' => [
                'VEHICLES_LIST',
                'VEHICLES_EDIT',
                'VEHICLES_DELETE',
                'VEHICLES_ADD',
                'SELFSERVE_LIST',
                'SELFSERVE_EDIT',
                'SELFSERVE_DELETE',
                'SELFSERVE_ADD',
                'BOOKINGS_LIST',
                'BOOKINGS_EDIT',
                'BOOKINGS_DELETE',
                'BOOKINGS_ADD',
                'ORDERS_LIST',
                'ORDERS_EDIT',
                'SUBUSERS_LIST',
                'SUBUSERS_EDIT',
                'SUBUSERS_DELETE',
                'SUBUSERS_ADD',
            ],
        ],
    ];

    /**
     * @var array<string, array{group:string,capability:string}>
     */
    private const PERMISSION_CAPABILITIES = [
        'VEHICLES_LIST' => ['group' => 'vehicles', 'capability' => 'view_vehicles'],
        'VEHICLES_EDIT' => ['group' => 'vehicles', 'capability' => 'edit_vehicles'],
        'VEHICLES_DELETE' => ['group' => 'vehicles', 'capability' => 'delete_vehicles'],
        'VEHICLES_ADD' => ['group' => 'vehicles', 'capability' => 'add_vehicles'],
        'SELFSERVE_LIST' => ['group' => 'selfserve', 'capability' => 'view_selfserve'],
        'SELFSERVE_EDIT' => ['group' => 'selfserve', 'capability' => 'edit_selfserve'],
        'SELFSERVE_DELETE' => ['group' => 'selfserve', 'capability' => 'delete_selfserve'],
        'SELFSERVE_ADD' => ['group' => 'selfserve', 'capability' => 'start_selfserve'],
        'BOOKINGS_LIST' => ['group' => 'bookings', 'capability' => 'view_bookings'],
        'BOOKINGS_EDIT' => ['group' => 'bookings', 'capability' => 'edit_bookings'],
        'BOOKINGS_DELETE' => ['group' => 'bookings', 'capability' => 'delete_bookings'],
        'BOOKINGS_ADD' => ['group' => 'bookings', 'capability' => 'add_bookings'],
        'ORDERS_LIST' => ['group' => 'orders', 'capability' => 'view_orders'],
        'ORDERS_EDIT' => ['group' => 'orders', 'capability' => 'edit_orders'],
        'SUBUSERS_LIST' => ['group' => 'driver_management', 'capability' => 'view_drivers'],
        'SUBUSERS_EDIT' => ['group' => 'driver_management', 'capability' => 'edit_driver_access'],
        'SUBUSERS_DELETE' => ['group' => 'driver_management', 'capability' => 'disable_driver_access'],
        'SUBUSERS_ADD' => ['group' => 'driver_management', 'capability' => 'invite_drivers'],
    ];

    /**
     * @var array<int, string>
     */
    private const GROUP_ORDER = [
        'vehicles',
        'selfserve',
        'bookings',
        'orders',
        'driver_management',
    ];

    /**
     * @return array<string, mixed>
     */
    public function accessModel(): array
    {
        return [
            'templates' => $this->templates(),
            'groups' => $this->groups(),
        ];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function templates(): array
    {
        $templates = [];
        foreach (self::TEMPLATES as $key => $template) {
            $templates[] = [
                'key' => $key,
                'label' => $template['label'],
                'description' => $template['description'],
                'enabled' => $template['enabled'],
                'permissions' => array_values($template['permissions']),
                'permission_groups' => $this->permissionGroups($template['permissions']),
            ];
        }

        return $templates;
    }

    /**
     * @return array<int, array{key:string,capabilities:array<int,string>}>
     */
    public function groups(): array
    {
        $groups = [];
        foreach (self::GROUP_ORDER as $group) {
            $capabilities = [];
            foreach (self::PERMISSION_CAPABILITIES as $capability) {
                if ($capability['group'] === $group) {
                    $capabilities[] = $capability['capability'];
                }
            }
            $groups[] = [
                'key' => $group,
                'capabilities' => array_values(array_unique($capabilities)),
            ];
        }

        return $groups;
    }

    /**
     * @return array{enabled:bool,permissions:array<int,string>}
     */
    public function expandTemplate(string $templateKey): array
    {
        $key = $this->normalizeTemplateKey($templateKey);
        if ($key === null || $key === self::TEMPLATE_CUSTOM) {
            throw new \InvalidArgumentException('Unknown driver access template.');
        }

        return [
            'enabled' => self::TEMPLATES[$key]['enabled'],
            'permissions' => array_values(self::TEMPLATES[$key]['permissions']),
        ];
    }

    /**
     * @return array{enabled:bool,permissions:array<int,string>}|null
     */
    public function expandTemplateForWritePayload(?string $templateKey): ?array
    {
        $key = $this->normalizeTemplateKey($templateKey);
        if ($key === self::TEMPLATE_CUSTOM) {
            return null;
        }

        if ($key === null) {
            throw new \InvalidArgumentException('Unknown driver access template.');
        }

        return $this->expandTemplate($key);
    }

    public function normalizeTemplateKey(?string $templateKey): ?string
    {
        if ($templateKey === null) {
            return null;
        }

        $key = strtolower(trim($templateKey));
        if ($key === self::TEMPLATE_CUSTOM) {
            return self::TEMPLATE_CUSTOM;
        }

        return array_key_exists($key, self::TEMPLATES) ? $key : null;
    }

    /**
     * @param array<int, string> $permissions
     */
    public function classify(array $permissions, bool $enabled = true): string
    {
        $normalized = $this->normalizePermissions($permissions);
        if (!$enabled || $normalized === []) {
            return self::TEMPLATE_DEACTIVATED;
        }

        foreach (self::TEMPLATES as $key => $template) {
            if (!$template['enabled']) {
                continue;
            }

            if ($normalized === $this->normalizePermissions($template['permissions'])) {
                return $key;
            }
        }

        return self::TEMPLATE_CUSTOM;
    }

    /**
     * @param array<int, string> $permissions
     * @return array<int, array{key:string,capabilities:array<int,string>}>
     */
    public function permissionGroups(array $permissions): array
    {
        $permissions = $this->normalizePermissions($permissions);
        $groups = [];
        foreach ($permissions as $permission) {
            $capability = self::PERMISSION_CAPABILITIES[$permission] ?? null;
            if ($capability === null) {
                continue;
            }

            $group = $capability['group'];
            $groups[$group] ??= [];
            $groups[$group][] = $capability['capability'];
        }

        $payload = [];
        foreach (self::GROUP_ORDER as $group) {
            if (!isset($groups[$group])) {
                continue;
            }

            $payload[] = [
                'key' => $group,
                'capabilities' => array_values(array_unique($groups[$group])),
            ];
        }

        return $payload;
    }

    /**
     * @param array<int, string> $permissions
     * @return array<int, string>
     */
    private function normalizePermissions(array $permissions): array
    {
        $normalized = [];
        foreach ($permissions as $permission) {
            if ($permission instanceof subusers_permission_node_key) {
                $permission = $permission->name;
            }
            if (!is_string($permission)) {
                continue;
            }
            $permission = strtoupper(trim($permission));
            if ($permission !== '' && subusers_permission_node_key::tryFrom($permission) !== null) {
                $normalized[] = $permission;
            }
        }

        $normalized = array_values(array_unique($normalized));
        sort($normalized);
        return $normalized;
    }
}
