<?php

declare(strict_types=1);

namespace Maestro\Core\Support;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Maestro\Core\Models\MaestroModule;

/**
 * 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,
     *     permissions: list<string>,
     *     roles: list<string>,
     *     enabled_module_slugs: list<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'),
            'permissions' => self::permissionNames($user),
            'roles' => self::roleNames($user),
            'enabled_module_slugs' => self::enabledModuleSlugs(),
        ];
    }

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

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

    /**
     * @return list<string>
     */
    private static function permissionNames(Authenticatable $user): array
    {
        if (! method_exists($user, 'getAllPermissions')) {
            return [];
        }

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

    /**
     * @return list<string>
     */
    private static function roleNames(Authenticatable $user): array
    {
        if (! method_exists($user, 'getRoleNames')) {
            return [];
        }

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

    /**
     * @return list<string>
     */
    private static function enabledModuleSlugs(): array
    {
        if (! MaestroModule::query()->getQuery()->getConnection()->getSchemaBuilder()->hasTable('maestro_modules')) {
            return [];
        }

        return MaestroModule::query()
            ->where('is_enabled', true)
            ->orderBy('sort_order')
            ->orderBy('id')
            ->pluck('slug')
            ->values()
            ->all();
    }
}
