<?php

namespace Tests\Feature;

use App\Models\Company;
use App\Models\User;
use App\Services\TenantRoleService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;

class MobileCompatApiTest extends TestCase
{
    use RefreshDatabase;

    private function sampleFaceData(): string
    {
        // 1x1 PNG
        return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO8WgN8AAAAASUVORK5CYII=';
    }

    private function staffWithAttendanceView(array $overrides = []): User
    {
        $suffix = strtolower(Str::random(6));
        $company = Company::query()->create([
            'name' => 'Face Co '.$suffix,
            'short_name' => 'F'.strtoupper($suffix),
            'email' => 'face-'.$suffix.'@example.com',
            'status' => 'active',
        ]);
        $roles = TenantRoleService::syncAllDefaultRolesForCompany((int) $company->id);

        return User::factory()->create(array_merge([
            'company_id' => $company->id,
            'role_id' => $roles['employee']->id,
            'user_type' => User::USER_TYPE_STAFF,
            'allow_login' => true,
        ], $overrides));
    }

    public function test_hrms_login_alias_returns_token_with_valid_credentials(): void
    {
        User::factory()->create([
            'email' => 'legacy-login@example.com',
            'password' => bcrypt('password'),
            'allow_login' => true,
        ]);

        $response = $this->postJson('/api/hrms/login', [
            'email' => 'legacy-login@example.com',
            'password' => 'password',
        ]);

        $response->assertOk();
        $response->assertJsonStructure(['user', 'token', 'token_type']);
        $response->assertJsonPath('user.email', 'legacy-login@example.com');
    }

    public function test_non_manager_cannot_register_face_for_other_user(): void
    {
        $actor = User::factory()->create([
            'company_id' => 11,
            'is_superadmin' => false,
        ]);
        $target = User::factory()->create([
            'company_id' => 11,
        ]);

        Sanctum::actingAs($actor);

        $response = $this->postJson('/api/face/register', [
            'user_id' => $target->id,
            'face_data' => $this->sampleFaceData(),
        ]);

        $response->assertStatus(403);
    }

    public function test_manager_can_register_and_sync_face_for_tenant_user(): void
    {
        $manager = User::factory()->create([
            'company_id' => 55,
            'is_superadmin' => true,
        ]);
        $sameTenant = User::factory()->create([
            'company_id' => 55,
            'employee_number' => 'EMP-55',
        ]);
        $otherTenant = User::factory()->create([
            'company_id' => 56,
        ]);

        Sanctum::actingAs($manager);

        $registerResponse = $this->postJson('/api/face/register', [
            'user_id' => $sameTenant->id,
            'face_data' => $this->sampleFaceData(),
            'overwrite' => true,
            'is_update' => true,
        ]);
        $registerResponse->assertStatus(201);
        $registerResponse->assertJsonPath('user_id', $sameTenant->id);

        $syncResponse = $this->getJson('/api/face/sync');
        $syncResponse->assertOk();
        $syncResponse->assertJsonFragment([
            'user_id' => $sameTenant->id,
            'company_id' => 55,
        ]);
        $syncResponse->assertJsonMissing([
            'user_id' => $otherTenant->id,
            'company_id' => 56,
        ]);
    }

    public function test_users_missing_faces_returns_only_same_tenant_staff(): void
    {
        $manager = User::factory()->create([
            'company_id' => 10,
            'is_superadmin' => true,
        ]);
        $staffWithoutFace = User::factory()->create([
            'company_id' => 10,
            'name' => 'Staff Missing Face',
        ]);
        $staffWithFace = User::factory()->create([
            'company_id' => 10,
            'name' => 'Staff With Face',
        ]);
        $differentTenantStaff = User::factory()->create([
            'company_id' => 99,
            'name' => 'Other Tenant Staff',
        ]);

        Sanctum::actingAs($manager);
        $this->postJson('/api/face/register', [
            'user_id' => $staffWithFace->id,
            'face_data' => $this->sampleFaceData(),
        ])->assertStatus(201);

        $response = $this->getJson('/api/users/missing-faces');

        $response->assertOk();
        $response->assertJsonFragment([
            'id' => $staffWithoutFace->id,
            'name' => 'Staff Missing Face',
        ]);
        $response->assertJsonMissing([
            'id' => $staffWithFace->id,
            'name' => 'Staff With Face',
        ]);
        $response->assertJsonMissing([
            'id' => $differentTenantStaff->id,
            'name' => 'Other Tenant Staff',
        ]);
    }

    public function test_users_list_returns_has_face_id_flag(): void
    {
        $manager = User::factory()->create([
            'company_id' => 44,
            'is_superadmin' => true,
        ]);
        $withoutFace = User::factory()->create([
            'company_id' => 44,
            'name' => 'Without Face',
        ]);
        $withFace = User::factory()->create([
            'company_id' => 44,
            'name' => 'With Face',
        ]);

        Sanctum::actingAs($manager);
        $this->postJson('/api/face/register', [
            'user_id' => $withFace->id,
            'face_data' => $this->sampleFaceData(),
        ])->assertStatus(201);

        $response = $this->getJson('/api/users');
        $response->assertOk();
        $response->assertJsonFragment([
            'id' => $withoutFace->id,
            'name' => 'Without Face',
            'has_face_id' => false,
        ]);
        $response->assertJsonFragment([
            'id' => $withFace->id,
            'name' => 'With Face',
            'has_face_id' => true,
        ]);
    }

    public function test_face_login_returns_token_for_registered_face(): void
    {
        if (! function_exists('imagecreatefromstring') || ! function_exists('imagescale')) {
            $this->markTestSkipped('GD extension is required for face login hash matching.');
        }

        config(['hrms_auth.face_login_enabled' => true]);

        $user = $this->staffWithAttendanceView([
            'email' => 'face-login@example.com',
        ]);

        Sanctum::actingAs($user);
        $this->postJson('/api/face/register', [
            'user_id' => $user->id,
            'face_data' => $this->sampleFaceData(),
        ])->assertStatus(201);

        $response = $this->postJson('/api/face/login', [
            'face_data' => $this->sampleFaceData(),
            'email' => 'face-login@example.com',
            'company_id' => $user->company_id,
        ]);

        $response->assertOk();
        $response->assertJsonStructure(['user', 'token', 'token_type']);
        $response->assertJsonPath('user.id', $user->id);
    }

    public function test_face_attendance_returns_422_for_unmatched_face(): void
    {
        if (! function_exists('imagecreatefromstring') || ! function_exists('imagescale')) {
            $this->markTestSkipped('GD extension is required for face login hash matching.');
        }

        $user = $this->staffWithAttendanceView([
            'email' => 'registered-face@example.com',
        ]);

        Sanctum::actingAs($user);
        $this->postJson('/api/face/register', [
            'user_id' => $user->id,
            'face_data' => $this->sampleFaceData(),
        ])->assertStatus(201);

        $differentFace = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAAB6XfxMAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';

        $response = $this->postJson('/api/face/attendance', [
            'mode' => 'login',
            'face_data' => $differentFace,
            'company_id' => $user->company_id,
        ]);

        $response->assertStatus(422);
        $response->assertJsonPath('message', 'Face not registered. Please use a registered face.');
    }

    public function test_face_attendance_login_captures_attendance(): void
    {
        if (! function_exists('imagecreatefromstring') || ! function_exists('imagescale')) {
            $this->markTestSkipped('GD extension is required for face login hash matching.');
        }

        $user = $this->staffWithAttendanceView([
            'email' => 'face-attendance@example.com',
        ]);

        Sanctum::actingAs($user);
        $this->postJson('/api/face/register', [
            'user_id' => $user->id,
            'face_data' => $this->sampleFaceData(),
        ])->assertStatus(201);

        $response = $this->postJson('/api/face/attendance', [
            'mode' => 'login',
            'face_data' => $this->sampleFaceData(),
            'company_id' => $user->company_id,
        ]);

        $response->assertOk();
        $response->assertJsonPath('mode', 'login');
        $response->assertJsonPath('user.id', $user->id);
        $response->assertJsonStructure(['attendance', 'captured_at']);
    }
}
