<?php

namespace Tests\Feature;

use App\Models\AttendanceRegularization;
use App\Models\Company;
use App\Models\User;
use App\Services\TenantRoleService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Tests\TestCase;

class AttendanceRegularizationApprovalTest extends TestCase
{
    use RefreshDatabase;

    private function seedCompany(): array
    {
        $suffix = strtolower(Str::random(6));
        $company = Company::query()->create([
            'name' => 'Reg Co '.$suffix,
            'short_name' => 'R'.strtoupper($suffix),
            'email' => 'reg-'.$suffix.'@example.com',
            'status' => 'active',
        ]);

        return TenantRoleService::syncAllDefaultRolesForCompany((int) $company->id);
    }

    private function userWithRole(int $companyId, string $roleName, array $overrides = []): User
    {
        $roles = TenantRoleService::syncAllDefaultRolesForCompany($companyId);

        return User::factory()->create(array_merge([
            'company_id' => $companyId,
            'role_id' => $roles[$roleName]->id,
            'user_type' => User::USER_TYPE_STAFF,
            'allow_login' => true,
        ], $overrides));
    }

    private function pendingRegularization(int $companyId, User $requester): AttendanceRegularization
    {
        return AttendanceRegularization::query()->create([
            'company_id' => $companyId,
            'user_id' => $requester->id,
            'date' => now()->toDateString(),
            'requested_clock_in' => now()->setTime(9, 0),
            'requested_clock_out' => now()->setTime(18, 0),
            'reason' => 'Missed punch',
            'status' => AttendanceRegularization::STATUS_PENDING,
        ]);
    }

    public function test_admin_can_approve_when_employee_has_manager(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['admin']->company_id;

        $manager = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['manager']->id,
            'user_type' => User::USER_TYPE_STAFF,
        ]);
        $employee = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['employee']->id,
            'report_to' => $manager->id,
            'user_type' => User::USER_TYPE_STAFF,
        ]);
        $admin = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['admin']->id,
            'user_type' => User::USER_TYPE_STAFF,
        ]);

        $regularization = $this->pendingRegularization($companyId, $employee);

        $this->assertTrue($admin->canApproveRegularization($regularization));
    }

    public function test_hr_can_approve_when_employee_has_manager(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['hr']->company_id;

        $manager = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['manager']->id]);
        $employee = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['employee']->id,
            'report_to' => $manager->id,
        ]);
        $hr = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['hr']->id]);

        $regularization = $this->pendingRegularization($companyId, $employee);

        $this->assertTrue($hr->canApproveRegularization($regularization));
    }

    public function test_direct_manager_can_approve_team_request(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['manager']->company_id;

        $manager = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['manager']->id]);
        $employee = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['employee']->id,
            'report_to' => $manager->id,
        ]);

        $regularization = $this->pendingRegularization($companyId, $employee);

        $this->assertTrue($manager->canApproveRegularization($regularization));
    }

    public function test_unrelated_manager_cannot_approve_when_employee_has_manager(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['manager']->company_id;

        $assignedManager = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['manager']->id]);
        $otherManager = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['manager']->id]);
        $employee = User::factory()->create([
            'company_id' => $companyId,
            'role_id' => $roles['employee']->id,
            'report_to' => $assignedManager->id,
        ]);

        $regularization = $this->pendingRegularization($companyId, $employee);

        $this->assertFalse($otherManager->canApproveRegularization($regularization));
    }

    public function test_employee_cannot_approve_requests(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['employee']->company_id;

        $employee = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['employee']->id]);
        $peer = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['employee']->id]);

        $regularization = $this->pendingRegularization($companyId, $peer);

        $this->assertFalse($employee->canApproveRegularization($regularization));
    }

    public function test_admin_sees_all_company_requests_on_index(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['admin']->company_id;

        $employee = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['employee']->id]);
        $admin = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['admin']->id]);

        $this->pendingRegularization($companyId, $employee);

        $response = $this->actingAs($admin)->get(route('attendance-regularizations.index'));

        $response->assertOk();
        $response->assertSee('Missed punch');
    }

    public function test_employee_sees_only_own_requests_on_index(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['employee']->company_id;

        $employee = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['employee']->id]);
        $peer = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['employee']->id]);

        $this->pendingRegularization($companyId, $employee);
        AttendanceRegularization::query()->create([
            'company_id' => $companyId,
            'user_id' => $peer->id,
            'date' => now()->subDay()->toDateString(),
            'requested_clock_in' => now()->subDay()->setTime(9, 0),
            'reason' => 'Peer request',
            'status' => AttendanceRegularization::STATUS_PENDING,
        ]);

        $response = $this->actingAs($employee)->get(route('attendance-regularizations.index'));

        $response->assertOk();
        $response->assertSee('Missed punch');
        $response->assertDontSee('Peer request');
    }

    public function test_finance_user_cannot_open_regularizations_index(): void
    {
        $roles = $this->seedCompany();
        $companyId = (int) $roles['finance']->company_id;
        $finance = User::factory()->create(['company_id' => $companyId, 'role_id' => $roles['finance']->id]);

        $this->actingAs($finance)
            ->get(route('attendance-regularizations.index'))
            ->assertForbidden();
    }
}
