<?php

declare(strict_types=1);

namespace App\Application\Admin;

use App\Domain\Auth\AuthenticatedPrincipal;
use App\Domain\Auth\TokenKind;
use App\Infrastructure\Auth\UserRepository;
use App\Infrastructure\Http\Middleware\TokenAuthenticationMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
 * `GET /api/v1/admin/me` — returns whoever is currently calling.
 *
 * Three branches:
 *  - admin token, no user binding   → role from token, source=admin-token,
 *    no user_id / email / display_name.
 *  - admin token bound to a user    → role from token, source from user
 *    record's is_local flag (M14 territory; reachable now if a future
 *    feature sets userId on admin tokens).
 *  - service token + impersonation  → role and identity from the user.
 */
final class MeController
{
    public function __construct(private readonly UserRepository $users)
    {
    }

    public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $principal = $request->getAttribute(TokenAuthenticationMiddleware::ATTR_PRINCIPAL);
        if (!$principal instanceof AuthenticatedPrincipal) {
            return self::json($response, 401, ['error' => 'unauthorized']);
        }

        if ($principal->tokenKind === TokenKind::Admin && $principal->userId === null) {
            return self::json($response, 200, [
                'user_id' => null,
                'email' => null,
                'display_name' => null,
                'role' => $principal->role?->value,
                'is_local' => false,
                'source' => 'admin-token',
            ]);
        }

        if ($principal->userId === null) {
            // Defensive: should not happen — service-without-impersonation
            // is rejected upstream and reporter/consumer never reach here.
            return self::json($response, 401, ['error' => 'unauthorized']);
        }

        $user = $this->users->findById($principal->userId);
        if ($user === null) {
            return self::json($response, 403, ['error' => 'forbidden']);
        }

        $source = $principal->tokenKind === TokenKind::Admin
            ? 'admin-token'
            : ($user->isLocal ? 'local' : 'oidc');

        return self::json($response, 200, [
            'user_id' => $user->id,
            'email' => $user->email,
            'display_name' => $user->displayName,
            'role' => $user->role->value,
            'is_local' => $user->isLocal,
            'source' => $source,
        ]);
    }

    /**
     * @param array<string, mixed> $payload
     */
    private static function json(ResponseInterface $response, int $status, array $payload): ResponseInterface
    {
        $response = $response->withStatus($status)->withHeader('Content-Type', 'application/json');
        $response->getBody()->write((string) json_encode($payload));

        return $response;
    }
}
