<?php

declare(strict_types=1);

namespace Maestro\Core\Support;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;

/**
 * Builds the /api/user JSON payload for any Authenticatable model.
 * When the model uses Spatie's HasRoles / HasPermissions traits, permissions and roles are included.
 */
final class AuthenticatedUserApiPayload
{
    /**
     * @return array{
     *     id: mixed,
     *     name: string|null,
     *     email: string|null,
     *     organization_id: mixed,
     *     permissions: Collection<int, string>,
     *     roles: Collection<int, string>
     * }
     */
    public static function toArray(?Authenticatable $user): array
    {
        if ($user === null) {
            abort(401);
        }

        return [
            'id' => self::attribute($user, 'id') ?? $user->getAuthIdentifier(),
            'name' => self::attribute($user, 'name'),
            'email' => self::attribute($user, 'email'),
            'organization_id' => self::attribute($user, 'organization_id'),
            'permissions' => self::permissionNames($user),
            'roles' => self::roleNames($user),
        ];
    }

    private static function attribute(Authenticatable $user, string $key): mixed
    {
        if (! method_exists($user, 'getAttribute')) {
            return null;
        }

        /** @var Model $user */
        return $user->getAttribute($key);
    }

    /**
     * @return Collection<int, string>
     */
    private static function permissionNames(Authenticatable $user): Collection
    {
        if (! method_exists($user, 'getAllPermissions')) {
            return collect();
        }

        return $user->getAllPermissions()->pluck('name')->values();
    }

    /**
     * @return Collection<int, string>
     */
    private static function roleNames(Authenticatable $user): Collection
    {
        if (! method_exists($user, 'getRoleNames')) {
            return collect();
        }

        return $user->getRoleNames()->values();
    }
}
