<?php

namespace Tests\Feature\Api;

use App\Models\Device;
use App\Models\Employee;
use App\Models\FaceTemplate;
use App\Models\Site;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Tests\TestCase;

class TemplatesTest extends TestCase
{
    use RefreshDatabase;

    protected function makeDevice(): array
    {
        $site = Site::factory()->create();
        $token = Str::random(64);
        $device = Device::factory()->create(['site_id' => $site->id, 'token_hash' => hash('sha256', $token)]);

        return [$device, $token];
    }

    protected function embedding(): string
    {
        return base64_encode(pack('f*', ...array_fill(0, 512, 0.02)));
    }

    public function test_enrollment_upload_creates_template_and_returns_version(): void
    {
        [, $token] = $this->makeDevice();
        $employee = Employee::factory()->create(['consent_on' => now()->toDateString()]);

        $response = $this->withHeaders(['X-Device-Token' => $token])->postJson('/api/v1/templates', [
            'emp_id' => $employee->emp_id,
            'embedding_b64' => $this->embedding(),
            'dim' => 512,
            'model' => 'buffalo_l/arcface',
            'quality' => 0.95,
            'captured_at' => now()->toIso8601String(),
        ]);

        $response->assertOk();
        $response->assertJsonStructure(['template_id', 'version']);
        $this->assertEquals(1, $response->json('version'));
        $this->assertDatabaseCount('face_templates', 1);
    }

    public function test_enrollment_unknown_emp_id_returns_422(): void
    {
        [, $token] = $this->makeDevice();

        $response = $this->withHeaders(['X-Device-Token' => $token])->postJson('/api/v1/templates', [
            'emp_id' => 'EMP9999',
            'embedding_b64' => $this->embedding(),
            'dim' => 512,
            'model' => 'buffalo_l/arcface',
        ]);

        $response->assertStatus(422);
        $response->assertJsonPath('error.code', 'unknown_emp_id');
    }

    public function test_enrollment_without_consent_returns_422(): void
    {
        [, $token] = $this->makeDevice();
        $employee = Employee::factory()->withoutConsent()->create();

        $response = $this->withHeaders(['X-Device-Token' => $token])->postJson('/api/v1/templates', [
            'emp_id' => $employee->emp_id,
            'embedding_b64' => $this->embedding(),
            'dim' => 512,
            'model' => 'buffalo_l/arcface',
        ]);

        $response->assertStatus(422);
        $response->assertJsonPath('error.code', 'consent_missing');
    }

    public function test_delta_sync_includes_inactive_templates_for_removal(): void
    {
        [, $token] = $this->makeDevice();
        $employee = Employee::factory()->create();

        $active = FaceTemplate::factory()->create(['employee_id' => $employee->id, 'updated_at' => now()->subDays(5)]);
        $cutoff = now()->subDay()->toIso8601String();
        $inactive = FaceTemplate::factory()->inactive()->create(['employee_id' => $employee->id]);

        $response = $this->withHeaders(['X-Device-Token' => $token])->getJson('/api/v1/templates?since='.urlencode($cutoff));
        $response->assertOk();

        $ids = collect($response->json('templates'))->pluck('template_id')->all();
        $this->assertContains($inactive->id, $ids);
        $this->assertNotContains($active->id, $ids);

        $match = collect($response->json('templates'))->firstWhere('template_id', $inactive->id);
        $this->assertFalse($match['active']);
    }

    public function test_full_snapshot_returns_only_active_templates(): void
    {
        [, $token] = $this->makeDevice();
        $employee = Employee::factory()->create();
        $active = FaceTemplate::factory()->create(['employee_id' => $employee->id]);
        $inactive = FaceTemplate::factory()->inactive()->create(['employee_id' => $employee->id]);

        $response = $this->withHeaders(['X-Device-Token' => $token])->getJson('/api/v1/templates');
        $response->assertOk();

        $ids = collect($response->json('templates'))->pluck('template_id')->all();
        $this->assertContains($active->id, $ids);
        $this->assertNotContains($inactive->id, $ids);
    }
}
