<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Features\Agent\Models\Agent;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Route;
use Tests\TestCase;

class VerifyAgentSignatureTest extends TestCase
{
    use RefreshDatabase;

    private Agent $agent;
    private string $hmacSecret = 'super-secret-hmac-key-for-monster-guard-12345';

    protected function setUp(): void
    {
        parent::setUp();

        $this->agent = Agent::create([
            'domain' => 'test-domain.com',
            'site_name' => 'Test Site',
            'status' => 'active',
            'hmac_secret' => $this->hmacSecret,
        ]);

        Route::middleware('agent.auth')
            ->post('/api/v1/test/agent-only', function () {
                return response()->json(['success' => true]);
            });
    }

    public function test_fails_without_headers(): void
    {
        $response = $this->postJson('/api/v1/test/agent-only', []);
        $response->assertStatus(401)
            ->assertJsonPath('code', 'missing_headers')
            ->assertJsonPath('message', 'Unauthorized. Missing security signatures.');
    }

    public function test_fails_with_expired_timestamp(): void
    {
        $timestamp = time() - 100;
        $nonce = uniqid('', true);

        $response = $this->postJson('/api/v1/test/agent-only', [], [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => 'dummy-signature',
        ]);

        $response->assertStatus(401)
            ->assertJsonPath('code', 'timestamp_expired')
            ->assertJsonPath('message', 'Unauthorized. Request timestamp expired.');
    }

    public function test_succeeds_with_valid_hmac_signature(): void
    {
        $timestamp = time();
        $nonce = uniqid('', true);
        $body = json_encode(['payload' => 'valid']);

        $method = 'POST';
        $uri = '/api/v1/test/agent-only';

        $payload = implode('|', [
            $method,
            $uri,
            $timestamp,
            $nonce,
            $body,
        ]);

        $signature = hash_hmac('sha256', $payload, $this->hmacSecret);

        $response = $this->postJson($uri, ['payload' => 'valid'], [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => $signature,
        ]);

        $response->assertStatus(200)
            ->assertJsonPath('success', true);
    }

    public function test_fails_with_modified_body(): void
    {
        $timestamp = time();
        $nonce = uniqid('', true);
        $body = json_encode(['payload' => 'valid']);

        $method = 'POST';
        $uri = '/api/v1/test/agent-only';

        $payload = implode('|', [
            $method,
            $uri,
            $timestamp,
            $nonce,
            $body,
        ]);

        $signature = hash_hmac('sha256', $payload, $this->hmacSecret);

        $response = $this->postJson($uri, ['payload' => 'MODIFIED-HACKED-VALUE'], [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => $signature,
        ]);

        $response->assertStatus(401)
            ->assertJsonPath('code', 'invalid_secret')
            ->assertJsonPath('message', 'Unauthorized. Security signature mismatch.');
    }

    public function test_replay_protection_blocks_identical_nonces(): void
    {
        $timestamp = time();
        $nonce = 'identical-test-nonce-123';
        $body = json_encode([]);

        $method = 'POST';
        $uri = '/api/v1/test/agent-only';

        $payload = implode('|', [
            $method,
            $uri,
            $timestamp,
            $nonce,
            $body,
        ]);

        $signature = hash_hmac('sha256', $payload, $this->hmacSecret);

        $headers = [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => $signature,
        ];

        $response1 = $this->postJson($uri, [], $headers);
        $response1->assertStatus(200);

        $response2 = $this->postJson($uri, [], $headers);
        $response2->assertStatus(401)
            ->assertJsonPath('code', 'replay_detected')
            ->assertJsonPath('message', 'Unauthorized. Replay attack detected.');
    }

    public function test_deleted_agent_returns_410(): void
    {
        $this->agent->update(['status' => 'deleted']);

        $timestamp = time();
        $nonce = uniqid('', true);
        $uri = '/api/v1/test/agent-only';
        $body = json_encode([]);

        $payload = implode('|', ['POST', $uri, $timestamp, $nonce, $body]);
        $signature = hash_hmac('sha256', $payload, $this->hmacSecret);

        $response = $this->postJson($uri, [], [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => $signature,
        ]);

        $response->assertStatus(410)
            ->assertJsonPath('code', 'agent_deleted');
    }

    public function test_suspended_agent_returns_403(): void
    {
        $this->agent->update(['status' => 'suspended']);

        $timestamp = time();
        $nonce = uniqid('', true);
        $uri = '/api/v1/test/agent-only';
        $body = json_encode([]);

        $payload = implode('|', ['POST', $uri, $timestamp, $nonce, $body]);
        $signature = hash_hmac('sha256', $payload, $this->hmacSecret);

        $response = $this->postJson($uri, [], [
            'X-AMG-Agent-ID' => $this->agent->id,
            'X-AMG-Timestamp' => (string) $timestamp,
            'X-AMG-Nonce' => $nonce,
            'X-AMG-Signature' => $signature,
        ]);

        $response->assertStatus(403)
            ->assertJsonPath('code', 'registration_revoked');
    }
}
