<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Features\Agent\Models\Agent;
use App\Features\Agent\Services\AgentLifecycleService;
use App\Features\Auth\Models\User;
use App\Features\Command\Models\Command;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AgentLifecycleTest extends TestCase
{
    use RefreshDatabase;

    private Agent $agent;
    private string $hmacSecret = 'lifecycle-test-hmac-secret-key-123456';

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

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

    /** @param array<string, mixed> $body */
    private function signedHeaders(string $method, string $uri, array $body = []): array
    {
        $timestamp = time();
        $nonce = uniqid('', true);
        $rawBody = json_encode($body);

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

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

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

    public function test_validate_endpoint_confirms_active_agent(): void
    {
        $uri = '/api/v1/agent/validate';

        $response = $this->postJson($uri, [], $this->signedHeaders('POST', $uri));

        $response->assertStatus(200)
            ->assertJsonPath('success', true)
            ->assertJsonPath('valid', true)
            ->assertJsonPath('agent_id', $this->agent->id);
    }

    public function test_deleted_agent_returns_410_on_validate(): void
    {
        $this->agent->update(['status' => 'deleted']);
        $uri = '/api/v1/agent/validate';

        $response = $this->postJson($uri, [], $this->signedHeaders('POST', $uri));

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

    public function test_unknown_agent_returns_404(): void
    {
        $uri = '/api/v1/agent/validate';
        $headers = $this->signedHeaders('POST', $uri);
        $headers['X-AMG-Agent-ID'] = '00000000-0000-0000-0000-000000000000';

        $response = $this->postJson($uri, [], $headers);

        $response->assertStatus(404)
            ->assertJsonPath('code', 'agent_not_found');
    }

    public function test_invalid_secret_returns_401_with_code(): void
    {
        $uri = '/api/v1/agent/validate';
        $headers = $this->signedHeaders('POST', $uri);
        $headers['X-AMG-Signature'] = str_repeat('a', 64);

        $response = $this->postJson($uri, [], $headers);

        $response->assertStatus(401)
            ->assertJsonPath('code', 'invalid_secret');
    }

    public function test_initiate_deletion_queues_factory_reset_command(): void
    {
        app(AgentLifecycleService::class)->initiateDeletion($this->agent);

        $this->agent->refresh();
        $this->assertSame('pending_deletion', $this->agent->status);
        $this->assertNotNull($this->agent->factory_reset_requested_at);

        $command = Command::where('agent_id', $this->agent->id)->first();
        $this->assertNotNull($command);
        $this->assertSame('factory_reset', $command->command);
        $this->assertSame('pending', $command->status);
    }

    public function test_factory_reset_complete_finalizes_agent(): void
    {
        app(AgentLifecycleService::class)->initiateDeletion($this->agent);
        $originalSecret = $this->agent->hmac_secret;

        Command::create([
            'agent_id' => $this->agent->id,
            'command' => 'sync_policy',
            'payload' => [],
            'status' => 'pending',
        ]);

        $uri = '/api/v1/agent/factory-reset-complete';
        $response = $this->postJson(
            $uri,
            ['reason' => 'factory_reset_command'],
            $this->signedHeaders('POST', $uri, ['reason' => 'factory_reset_command'])
        );

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

        $this->agent->refresh();
        $this->assertSame('deleted', $this->agent->status);
        $this->assertNotNull($this->agent->factory_reset_completed_at);
        $this->assertNotSame($originalSecret, $this->agent->hmac_secret);

        $this->assertSame(
            0,
            Command::where('agent_id', $this->agent->id)->whereIn('status', ['pending', 'sent'])->count()
        );
    }

    public function test_bulk_delete_action_queues_factory_reset(): void
    {
        $response = $this->actingAs($this->createAdminUser())
            ->postJson('/api/v1/agents/bulk', [
                'ids' => [$this->agent->id],
                'action' => 'delete',
            ]);

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

        $this->agent->refresh();
        $this->assertSame('pending_deletion', $this->agent->status);
        $this->assertTrue(
            Command::where('agent_id', $this->agent->id)->where('command', 'factory_reset')->exists()
        );
    }

    private function createAdminUser(): User
    {
        return User::create([
            'name' => 'Lifecycle Admin',
            'email' => 'lifecycle-admin@test.local',
            'password' => bcrypt('password'),
        ]);
    }
}
