<?php

namespace Tests\Feature;

use App\Models\AttendanceLog;
use App\Models\FingerprintMachine;
use App\Models\Role;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LocalConnectorTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        Role::create(['name' => 'siswa', 'label' => 'Siswa']);
    }

    public function test_connector_heartbeat_updates_machine_status_and_last_seen_at(): void
    {
        $machine = FingerprintMachine::create([
            'name' => 'Revo W-231N XI TKJ',
            'ip_address' => '192.168.0.106',
            'port' => '4370',
            'connection_type' => 'local_connector',
            'protocol' => 'local_connector',
            'connector_token' => 'TEST_TOKEN_123',
            'status' => 'offline',
        ]);

        $payload = [
            'machine_id' => $machine->id,
            'ip_address' => '192.168.0.106',
            'connector_host' => '192.168.0.106',
            'connector_port' => '8000',
            'device_info' => ['os' => 'Windows 10 Pro', 'agent_version' => '1.0.0'],
        ];

        $response = $this->withHeaders([
            'X-Connector-Token' => 'TEST_TOKEN_123',
        ])->postJson('/api/connector/heartbeat', $payload);

        $response->assertStatus(200);
        $response->assertJson([
            'success' => true,
        ]);

        $freshMachine = $machine->fresh();
        $this->assertEquals('online', $freshMachine->status);
        $this->assertNotNull($freshMachine->last_seen_at);
        $this->assertEquals('192.168.0.106', $freshMachine->connector_host);
    }

    public function test_connector_push_attendance_ingests_logs_and_prevents_duplicates(): void
    {
        $machine = FingerprintMachine::create([
            'name' => 'Revo W-231N XI TKJ',
            'ip_address' => '192.168.0.106',
            'port' => '4370',
            'connection_type' => 'local_connector',
            'protocol' => 'local_connector',
            'connector_token' => 'TEST_TOKEN_123',
            'status' => 'offline',
        ]);

        User::factory()->create([
            'nip_nis' => '8001',
            'is_active' => true,
        ]);

        $payload = [
            'machine_id' => $machine->id,
            'ip_address' => '192.168.0.106',
            'logs' => [
                [
                    'pin' => '8001',
                    'scan' => '2026-08-09 07:05:00',
                    'verify' => 'fingerprint',
                ],
                [
                    'pin' => '8001',
                    'scan' => '2026-08-09 07:05:00', // Duplicate log
                    'verify' => 'fingerprint',
                ],
            ],
        ];

        $response = $this->withHeaders([
            'X-Connector-Token' => 'TEST_TOKEN_123',
        ])->postJson('/api/connector/push-attendance', $payload);

        $response->assertStatus(200);
        $response->assertJson([
            'success' => true,
            'received' => 2,
            'inserted' => 1,
            'duplicates' => 1,
        ]);

        $this->assertDatabaseHas('attendance_logs', [
            'machine_id' => $machine->id,
            'raw_user_id' => '8001',
            'timestamp' => '2026-08-09 07:05:00',
        ]);
    }

    public function test_connector_api_validates_token_and_rejects_unauthorized_requests(): void
    {
        $machine = FingerprintMachine::create([
            'name' => 'Secure Connector Machine',
            'ip_address' => '192.168.0.106',
            'connection_type' => 'local_connector',
            'protocol' => 'local_connector',
            'connector_token' => 'SECRET_RIGHT_TOKEN',
            'status' => 'offline',
        ]);

        $payload = [
            'machine_id' => $machine->id,
        ];

        $response = $this->withHeaders([
            'X-Connector-Token' => 'WRONG_INVALID_TOKEN',
        ])->postJson('/api/connector/heartbeat', $payload);

        $response->assertStatus(401);
        $response->assertJson([
            'success' => false,
            'message' => 'CONNECTOR_AUTH_FAILED: Invalid or missing authentication token.',
        ]);
    }

    public function test_connector_diagnostic_command_runs_successfully(): void
    {
        FingerprintMachine::create([
            'name' => 'Revo W-231N Diagnostic Test',
            'ip_address' => '192.168.0.106',
            'port' => '4370',
            'connection_type' => 'local_connector',
            'protocol' => 'local_connector',
            'status' => 'online',
            'last_seen_at' => now(),
        ]);

        $this->artisan('fingerprint:connector-diagnostic')
            ->assertExitCode(0);
    }

    public function test_calculated_status_evaluates_online_stale_offline(): void
    {
        $machine = FingerprintMachine::create([
            'name' => 'Status Calculation Machine',
            'ip_address' => '192.168.0.106',
            'last_seen_at' => now(),
        ]);

        $this->assertEquals('online', $machine->calculatedStatus());

        $machine->update(['last_seen_at' => now()->subMinutes(5)]);
        $this->assertEquals('stale', $machine->calculatedStatus());

        $machine->update(['last_seen_at' => now()->subMinutes(15)]);
        $this->assertEquals('offline', $machine->calculatedStatus());

        // null last_seen_at = never connected (not just offline)
        $machine->update(['last_seen_at' => null]);
        $this->assertEquals('never_connected', $machine->calculatedStatus());
    }
}
