<?php

namespace modules\subusers\classes;

use modules\subusers\interfaces\subusers_user_grant_i;
use modules\subusers\traits\subuser_user_grant_t;
use modules\subusers\traits\subusers_user_permissions_t;
use modules\subusers\permissions\subusers_permission_nodes_bookings;
use modules\subusers\permissions\subusers_permission_nodes_orders;
use modules\subusers\permissions\subusers_permission_nodes_selfserve;
use modules\subusers\permissions\subusers_permission_nodes_subusers;
use modules\subusers\permissions\subusers_permission_nodes_vehicles;
use objects\subuser_grants_o;

class subuser_user_grant implements subusers_user_grant_i
{
    use subuser_user_grant_t,
        subusers_user_permissions_t;
    public int $subuser_id;
    public int $customer_number;
    /**
     * @var subusers_permission_node[] $permission_nodes An array of permission nodes that define the permissions granted to the subuser for this customer
     */
    protected array $permission_nodes;

    public function __construct(int $subuser_id, int $customer_number)
    {
        $this->subuser_id = $subuser_id;
        $this->customer_number = $customer_number;
        // Initialize all permission node containers to avoid uninitialized typed properties
        $this->bookings = new subusers_permission_nodes_bookings();
        $this->orders = new subusers_permission_nodes_orders();
        $this->selfserve = new subusers_permission_nodes_selfserve();
        $this->subusers = new subusers_permission_nodes_subusers();
        $this->vehicles = new subusers_permission_nodes_vehicles();
        // Get the grants and enable the permission nodes based on the grants
        $this->loadGrants();
    }

    public function loadGrants(): void
    {
        $subuser_grants_o = new subuser_grants_o();
        $subuser_grants = $subuser_grants_o->getGrantsForSubuserAndCustomer($this->subuser_id, $this->customer_number);
        // Loop through the permissions and enable the corresponding permission nodes
        foreach ($subuser_grants as $permission) {
            $this->enablePermissionNode($permission);
        }
    }

    private function enablePermissionNode(string $permission): void
    {
        // Get all properties extending the subusers_permission_nodes class
        $reflection = new \ReflectionClass($this);
        $properties = $reflection->getProperties();
        foreach ($properties as $property) {
            $propertyType = $property->getType();
            if ($propertyType && is_a($propertyType->getName(), subusers_permission_nodes::class, true)) {
                // Avoid accessing uninitialized typed properties
                if (method_exists($property, 'isInitialized') && !$property->isInitialized($this)) {
                    continue;
                }
                $container = $property->getValue($this);
                if ($container instanceof subusers_permission_nodes) {
                    $node = $container->getNodeByKey($permission);
                    if ($node !== null) {
                        $node->value = true;
                        return;
                    }
                }
            }
        }
    }

    /**
     * Check if a specific permission node is granted for this subuser/customer pair
     */
    public function hasNode(\modules\subusers\helpers\subusers_permission_node_key $key): bool
    {
        $reflection = new \ReflectionClass($this);
        $properties = $reflection->getProperties();
        foreach ($properties as $property) {
            $propertyType = $property->getType();
            if ($propertyType && is_a($propertyType->getName(), subusers_permission_nodes::class, true)) {
                // Avoid accessing uninitialized typed properties
                if (method_exists($property, 'isInitialized') && !$property->isInitialized($this)) {
                    continue;
                }
                $container = $property->getValue($this);
                if ($container instanceof subusers_permission_nodes) {
                    $node = $container->getNode($key);
                    if ($node !== null) {
                        return (bool)($node->value === true);
                    }
                }
            }
        }
        return false;
    }
}