<?php

namespace App\Services;

use App\Models\PersonalAccessToken;
use Modules\Auth\Entities\User;
use Modules\Role\Entities\Role;

class ActiveRoleService
{
    public static function resolveDefaultRole(User $user): ?Role
    {
        $roles = $user->roles;

        if ($roles->isEmpty()) {
            return null;
        }

        if ($roles->count() === 1) {
            return $roles->first();
        }

        if (config('active_role.prefer_member_on_login', true)) {
            $memberRole = $roles->first(fn (Role $role) => self::roleContext($role) === 'member');

            if ($memberRole) {
                return $memberRole;
            }
        }

        return $roles->first();
    }

    public static function assignToCurrentToken(User $user, Role $role): void
    {
        $token = $user->currentAccessToken();

        if ($token instanceof PersonalAccessToken) {
            $token->forceFill(['active_role_id' => $role->id])->save();
        }
    }

    public static function assignDefaultToToken(User $user, PersonalAccessToken $accessToken): void
    {
        $user->loadMissing('roles');

        $role = self::resolveDefaultRole($user);

        if ($role) {
            $accessToken->forceFill(['active_role_id' => $role->id])->save();
        }
    }

    public static function getActiveRole(User $user): ?Role
    {
        $user->loadMissing(['roles.permissions']);

        $token = $user->currentAccessToken();

        if ($token instanceof PersonalAccessToken && $token->active_role_id) {
            $role = $user->roles->firstWhere('id', $token->active_role_id);

            if ($role) {
                return $role;
            }
        }

        return self::resolveDefaultRole($user);
    }

    public static function switchRole(User $user, string $roleId): ?Role
    {
        $role = $user->roles()->where('roles.id', $roleId)->first();

        if (! $role) {
            return null;
        }

        self::assignToCurrentToken($user, $role);

        return $role->load('permissions');
    }

    public static function roleContext(Role $role): string
    {
        $context = $role->context ?? 'member';

        return in_array($context, ['admin', 'member'], true) ? $context : 'member';
    }

    public static function redirectPathForRole(Role $role): string
    {
        return self::roleContext($role) === 'admin'
            ? config('active_role.admin_redirect', '/profile')
            : config('active_role.member_redirect', '/profile');
    }

    /**
     * @return array<string, mixed>|null
     */
    public static function formatRole(?Role $role): ?array
    {
        if (! $role) {
            return null;
        }

        return [
            'id' => $role->id,
            'name' => $role->name,
            'fullname' => $role->fullname ?? null,
            'guard_name' => $role->guard_name,
            'context' => self::roleContext($role),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function sessionMeta(User $user): array
    {
        $activeRole = self::getActiveRole($user);

        return [
            'active_role' => self::formatRole($activeRole),
            'can_switch_role' => $user->roles->count() > 1,
            'redirect_path' => $activeRole
                ? self::redirectPathForRole($activeRole)
                : config('active_role.member_redirect', '/profile'),
        ];
    }
}
