<?php

namespace Middlewares;

use Libs\ResponseLib;
use Models\ApiUserModel;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;

class HmacAuthMiddleware
{
    private array $api_Key;

    public function __construct()
    {
        // Instancia a model e carrega as chaves API
        $apiUserModel = new ApiUserModel();
        $this->api_Key = $apiUserModel->getApiKeys();
    }

    public function __invoke(ServerRequestInterface $request, callable $next)
    {
        // 1. Extrai headers
        $signature = $request->getHeaderLine('x-signature');
        $apiUser = $request->getHeaderLine('x-user');
        $nonce = $request->getHeaderLine('x-nonce');

        if (empty($signature) || empty($apiUser) || empty($nonce)) {
            return ResponseLib::sendFail("Unauthorized: Missing signature or headers", [], "E_VALIDATE")->withStatus(401);
        }

        // 2. Verifica se nonce está dentro do intervalo
        $currentTime = time();
        if (abs($currentTime - (int) $nonce) > 2) {
            return ResponseLib::sendFail("Unauthorized: Invalid or expired nonce", [], "E_VALIDATE")->withStatus(401);
        }

        // 3. Verifica se o usuário é válido
        if (!isset($this->api_Key[$apiUser])) {
            return ResponseLib::sendFail("Unauthorized: Invalid API User", [], "E_VALIDATE")->withStatus(401);
        }

        $apiKey = $this->api_Key[$apiUser]['user_apikey'];
        $apiSecret = $this->api_Key[$apiUser]['user_apisecret'];
        $secret = $apiKey . "::" . $apiSecret;

        // 4. Monta mensagem para HMAC: <jsonBody>::<nonce>
        $rawBody = (string) $request->getBody();
        $message = $rawBody . "::" . $nonce;

        // 5. Calcula assinatura esperada
        $expectedSignature = hash_hmac('sha256', $message, $secret);

        // 6. Verifica assinatura
        if (!hash_equals($expectedSignature, $signature)) {
            return ResponseLib::sendFail("Unauthorized: Signature mismatch", [], "E_VALIDATE")->withStatus(401);
        }

        // 7. Tudo certo, adiciona atributos ao request e segue
        $request = $request
            ->withAttribute('api_user', $apiUser)
            ->withAttribute('api_user_id', $this->api_Key[$apiUser]['user_id']);

        return $next($request);
    }
}