<?php

namespace Modules\Auth\Services;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Modules\Auth\Models\Role;
use Modules\Auth\Repositories\PermissionRepository;
use Modules\Auth\Repositories\RoleRepository;
use Modules\Core\Enums\RolesEnum;

class RoleService
{
    protected $roleRepo;
    protected $permissionRepo;

    public function __construct(RoleRepository $roleRepo, PermissionRepository $permissionRepo)
    {
        $this->roleRepo = $roleRepo;
        $this->permissionRepo = $permissionRepo;

    }

    public function getRoleList()
    {
        $user = authUser();
        $isSuper = $user->hasRole(RolesEnum::SUPER_ADMIN->value);

        return $this->roleRepo->all($isSuper, ['id', 'title','name']);
    }

    public function getAllRoles(): array
    {
        $user = authUser();
        $isSuper = $user->hasRole(RolesEnum::SUPER_ADMIN->value);
        $roles = $this->roleRepo->allWithPermissions($isSuper);

        return $roles->map(function ($role) {
            return [
                'id' => $role->id,
                'title' => $role->title,
                'permissions_count' => $role->permissions_count,
                'permissions' => $role->permissions->pluck('name'),
            ];
        })->toArray();
    }

    public function getForRole(Role $role): array
    {
        return Cache::remember(
            $this->cacheKey($role),
            now()->addMinutes(30),
            fn () => $this->buildTree($role)
        );
    }

    protected function buildTree(Role $role): array
    {
        $permissions = $this->permissionRepo->allOrdered();

        $assigned = array_flip(
            $this->permissionRepo->rolePermissionNames($role)
        );

        $tree = [];

        foreach ($permissions as $permission) {
            $parts = explode('.', $permission->name);
            $module  = $permission->module ?? ucfirst($parts[0] ?? 'General');
            $feature = $parts[1] ?? 'general';
            $action  = $parts[2] ?? 'view';

            $tree[$module][$feature][] = [
                'id'       => $permission->id,
                'name'     => $permission->name,
                'action'   => $action,
                'label'    => ucfirst(str_replace('-', ' ', $action)),
                'assigned' => isset($assigned[$permission->name]),
            ];
        }

        return $tree;
    }

    public function updateRoleWithPermissions(Role $role, string $title, array $permissions): Role
    {
        DB::transaction(function () use ($role, $title, $permissions) {
            $role->update(['title' => $title]);

            $this->syncPermissions($role, $permissions);

            $this->clearCache($role);
        });

        return $role->fresh(['permissions']);
    }

    // Sync permissions, only assign what user can
    protected function syncPermissions(Role $role, array $permissions)
    {
        $user = authUser();

        if ($role->name === RolesEnum::SUPER_ADMIN->value) {
            return;
        }

        if ($user->hasRole(RolesEnum::SUPER_ADMIN->value)) {
           $role->syncPermissions($permissions ?? []);
            return;
        }

        $allowed = collect($permissions)
            ->filter(fn($perm) => $user->can($perm))
            ->toArray();

       $role->syncPermissions($allowed);
    }

    public function clearCache(Role $role): void
    {
        Cache::forget($this->cacheKey($role));
    }

    protected function cacheKey(Role $role): string
    {
        return "role_permission_tree_{$role->id}";
    }
}
