<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Features\Auth\Models\User;
use App\Features\Agent\Models\Agent;
use App\Features\Agent\Models\AgentGroup;
use App\Features\Agent\Models\TelegramProfile;
use App\Features\KeyManagement\Models\ActivationKey;
use App\Features\Policy\Models\Policy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class DashboardCrudTest extends TestCase
{
    use RefreshDatabase;

    private User $admin;

    protected function setUp(): void
    {
        parent::setUp();
        
        $this->admin = User::create([
            'name' => 'Manager',
            'email' => 'manager@gmail.com',
            'password' => bcrypt('Abc@@123'),
        ]);
    }

    public function test_unauthenticated_requests_are_blocked(): void
    {
        $response = $this->getJson('/api/v1/agents');
        $response->assertStatus(401);
    }

    public function test_agent_groups_crud_operations(): void
    {
        $this->actingAs($this->admin);

        // 1. Create group
        $responseCreate = $this->postJson('/api/v1/agent-groups', [
            'name' => 'VIP Clients',
            'description' => 'VIP hosting servers',
        ]);
        $responseCreate->assertStatus(201)
            ->assertJsonPath('group.name', 'VIP Clients');

        // 2. List groups
        $responseList = $this->getJson('/api/v1/agent-groups');
        $responseList->assertStatus(200)
            ->assertJsonCount(1, 'groups');

        $groupId = $responseCreate->json('group.id');

        // 3. Update group
        $responseUpdate = $this->putJson("/api/v1/agent-groups/{$groupId}", [
            'name' => 'VIP Server Hub',
            'description' => 'Updated hosting specs',
        ]);
        $responseUpdate->assertStatus(200)
            ->assertJsonPath('group.name', 'VIP Server Hub');

        // 4. Delete group
        $responseDelete = $this->deleteJson("/api/v1/agent-groups/{$groupId}");
        $responseDelete->assertStatus(200);

        $this->assertDatabaseMissing('agent_groups', ['id' => $groupId]);
    }

    public function test_telegram_profiles_crud_operations(): void
    {
        $this->actingAs($this->admin);

        // 1. Create profile
        $responseCreate = $this->postJson('/api/v1/telegram-profiles', [
            'name' => 'Emergency alerts',
            'bot_token' => 'BOT-TOKEN-1234',
            'chat_id' => 'CHAT-ID-1234',
            'is_default' => true,
        ]);
        $responseCreate->assertStatus(201)
            ->assertJsonPath('profile.is_default', true);

        $profileId = $responseCreate->json('profile.id');

        $agent = Agent::create([
            'domain' => 'client-telegram.com',
            'site_name' => 'Client Telegram Site',
            'status' => 'active',
            'hmac_secret' => 'secret123',
        ]);

        // 2. List profiles
        $responseList = $this->getJson('/api/v1/telegram-profiles');
        $responseList->assertStatus(200)
            ->assertJsonCount(1, 'profiles');

        // 3. Update profile
        $responseUpdate = $this->putJson("/api/v1/telegram-profiles/{$profileId}", [
            'name' => 'General notifications',
            'bot_token' => 'UPDATED-TOKEN',
            'chat_id' => 'UPDATED-CHAT-ID',
            'is_default' => false,
            'assigned_agent_ids' => [$agent->id],
        ]);
        $responseUpdate->assertStatus(200)
            ->assertJsonPath('profile.name', 'General notifications')
            ->assertJsonPath('profile.is_default', false)
            ->assertJsonPath('profile.agents_count', 1);

        $this->assertSame($profileId, $agent->refresh()->telegram_profile_id);

        // 4. Delete profile
        $responseDelete = $this->deleteJson("/api/v1/telegram-profiles/{$profileId}");
        $responseDelete->assertStatus(200);
    }

    public function test_agents_list_does_not_expose_sensitive_fields(): void
    {
        $this->actingAs($this->admin);

        $activationKey = ActivationKey::create([
            'key' => 'TEST-KEY-1234',
            'type' => 'client',
            'max_activations' => 5,
            'status' => 'active',
        ]);

        Agent::create([
            'domain' => 'plugin-testing.test',
            'site_name' => 'Plugin testing',
            'status' => 'active',
            'hmac_secret' => 'secret123',
            'activation_key_id' => $activationKey->id,
            'activation_key' => 'TEST-KEY-1234',
            'activated_at' => now(),
        ]);

        $response = $this->getJson('/api/v1/agents');
        $response->assertStatus(200);

        $agentPayload = $response->json('agents.0');
        $this->assertIsArray($agentPayload);
        $this->assertArrayNotHasKey('hmac_secret', $agentPayload);
        $this->assertArrayNotHasKey('activation_key', $agentPayload);
        $this->assertArrayNotHasKey('deactivation_token', $agentPayload);
    }

    public function test_agent_administration_and_deactivation_token(): void
    {
        $this->actingAs($this->admin);

        $agent = Agent::create([
            'domain' => 'client-blog.com',
            'site_name' => 'Client Blog',
            'status' => 'active',
            'hmac_secret' => 'secret123',
        ]);

        $group = AgentGroup::create(['name' => 'Hosting A']);
        $profile = TelegramProfile::create([
            'name' => 'VIP Chat',
            'bot_token' => 'token1',
            'chat_id' => 'chat1',
        ]);

        // 1. List agents
        $responseList = $this->getJson('/api/v1/agents');
        $responseList->assertStatus(200)
            ->assertJsonCount(1, 'agents');

        // 2. Update agent (assign group, telegram profile)
        $responseUpdate = $this->putJson("/api/v1/agents/{$agent->id}", [
            'group_id' => $group->id,
            'telegram_profile_id' => $profile->id,
            'status' => 'active',
            'site_name' => 'Client WordPress Blog',
        ]);
        $responseUpdate->assertStatus(200)
            ->assertJsonPath('agent.group_id', $group->id)
            ->assertJsonPath('agent.telegram_profile_id', $profile->id);

        // 3. Allow Deactivation
        $responseDeauth = $this->postJson("/api/v1/agents/{$agent->id}/allow-deactivation");
        $responseDeauth->assertStatus(200)
            ->assertJsonStructure(['success', 'deactivation_token', 'message']);

        $token = $responseDeauth->json('deactivation_token');
        $this->assertNotNull($token);

        // Assert database updated status and token
        $this->assertDatabaseHas('agents', [
            'id' => $agent->id,
            'status' => 'deactivation_allowed',
            'deactivation_token' => $token,
        ]);
    }

    public function test_policy_administration_retrieval_and_save(): void
    {
        $this->actingAs($this->admin);

        // 1. Get Global Policy (default baseline)
        $responseGet = $this->getJson('/api/v1/policies?scope=global');
        $responseGet->assertStatus(200)
            ->assertJsonPath('exists', false) // not in database yet, returns default
            ->assertJsonStructure(['exists', 'settings' => ['heartbeat_interval']]);

        // 2. Save Global Policy
        $settings = [
            'heartbeat_interval' => 120,
            'modules' => [
                'ip_blocking' => ['enabled' => true, 'settings' => []],
            ],
        ];

        $responseSave = $this->postJson('/api/v1/policies', [
            'scope' => 'global',
            'settings' => $settings,
        ]);
        $responseSave->assertStatus(200)
            ->assertJsonPath('success', true);

        // 3. Get Global Policy again (should exist now)
        $responseGet2 = $this->getJson('/api/v1/policies?scope=global');
        $responseGet2->assertStatus(200)
            ->assertJsonPath('exists', true)
            ->assertJsonPath('settings.heartbeat_interval', 120);
    }

    public function test_website_policy_retrieval_expands_partial_override_to_full_settings(): void
    {
        $this->actingAs($this->admin);

        $agent = Agent::create([
            'domain' => 'plugin-dev.test',
            'site_name' => 'A-monster Guard',
            'status' => 'active',
            'hmac_secret' => 'secret123',
        ]);

        Policy::create([
            'agent_id' => $agent->id,
            'settings' => [
                'phase1_pipeline_revision' => 'legacy-partial-policy',
                'modules' => [
                    'uploads_protection' => [
                        'enabled' => false,
                    ],
                ],
            ],
        ]);

        $response = $this->getJson("/api/v1/policies?scope=agent&agent_id={$agent->id}");

        $response->assertStatus(200)
            ->assertJsonPath('exists', true)
            ->assertJsonPath('settings.modules.uploads_protection.enabled', false)
            ->assertJsonPath('settings.modules.deactivation_protection.enabled', true)
            ->assertJsonStructure(['settings' => ['heartbeat_interval', 'modules']]);
    }

    public function test_activation_keys_crud_operations(): void
    {
        $this->actingAs($this->admin);

        // 1. Create Key
        $responseCreate = $this->postJson('/api/v1/activation-keys', [
            'type' => 'client',
            'max_activations' => 3,
            'allowed_domains' => 'domain.com',
            'notes' => 'Test key',
        ]);
        $responseCreate->assertStatus(201)
            ->assertJsonStructure(['success', 'key' => ['key', 'id']]);

        $keyId = $responseCreate->json('key.id');

        // 2. List Keys
        $responseList = $this->getJson('/api/v1/activation-keys');
        $responseList->assertStatus(200)
            ->assertJsonCount(1, 'keys');

        // 3. Update Key
        $responseUpdate = $this->putJson("/api/v1/activation-keys/{$keyId}", [
            'status' => 'suspended',
            'max_activations' => 5,
            'allowed_domains' => 'domain.com,other.com',
            'notes' => 'Suspended for audit',
        ]);
        $responseUpdate->assertStatus(200)
            ->assertJsonPath('key.status', 'suspended')
            ->assertJsonPath('key.max_activations', 5);

        // 4. Delete Key
        $responseDelete = $this->deleteJson("/api/v1/activation-keys/{$keyId}");
        $responseDelete->assertStatus(200);
    }
}
