<?php

use App\Enums\IsPaid;
use App\Enums\SalaryAdjustmentType;
use App\Livewire\Studio\Finance\Payroll;
use App\Models\Employee;
use App\Models\Payroll as PayrollModel;
use App\Models\PayrollAdjustment;
use App\Models\User;
use Carbon\Carbon;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

beforeEach(function () {
    $this->setupUser();

    $role = Role::firstOrCreate(['name' => 'Owner']);
    Permission::firstOrCreate(['name' => 'view payroll']);
    Permission::firstOrCreate(['name' => 'manage adjustment']);
    $role->givePermissionTo(['view payroll', 'manage adjustment']);
    $this->user->assignRole($role);
});

it('renders the payroll page correctly', function () {
    PayrollModel::factory()->create([
        'user_id' => $this->user->id,
        'period_month' => Carbon::now()->format('Y-m'),
        'is_paid' => \App\Enums\IsPaid::NOT_PAID,
    ]);

    $this->actingAs($this->user)
        ->get(route('studio.finance.payroll.index'))
        ->assertOk()
        ->assertSeeLivewire(Payroll::class);
});

it('can open modal for adjustment', function () {
    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->call('openModal', 'create', 'Tambah Penyesuaian')
        ->assertSet('method', 'create')
        ->assertSet('modalTitle', 'Tambah Penyesuaian');
});

it('shows validation errors on adjustment form', function () {
    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->call('create')
        ->assertHasErrors([
            'form.user_ids' => 'required',
            'form.type' => 'required',
            'form.amount' => 'required',
            'form.description' => 'required',
        ]);
});

it('can add a bonus adjustment', function () {
    $employeeUser = User::factory()->active()->create();
    Employee::factory()->create(['user_id' => $employeeUser->id, 'base_salary' => 5000000]);

    // Create payroll for the current month
    $payroll = PayrollModel::factory()->create([
        'user_id' => $employeeUser->id,
        'period_month' => Carbon::now()->format('Y-m'),
        'base_salary' => 5000000,
        'bonus' => 0,
        'deduction' => 0,
        'total_salary' => 5000000,
    ]);

    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->set('form.user_ids', [$employeeUser->id])
        ->set('form.type', SalaryAdjustmentType::BONUS->value)
        ->set('form.amount', '500000')
        ->set('form.description', 'Bonus Performance')
        ->call('create')
        ->assertHasNoErrors()
        ->assertDispatched('refreshDatatable');

    $payroll->refresh();
    expect($payroll->bonus)->toBe(500000);
    expect($payroll->total_salary)->toBe(5500000);

    $this->assertDatabaseHas('payroll_adjustments', [
        'payroll_id' => $payroll->id,
        'type' => SalaryAdjustmentType::BONUS->value,
        'amount' => 500000,
        'description' => 'Bonus Performance',
    ]);
});

it('can add a deduction adjustment', function () {
    $employeeUser = User::factory()->active()->create();
    Employee::factory()->create(['user_id' => $employeeUser->id, 'base_salary' => 5000000]);

    // Create payroll for the current month
    $payroll = PayrollModel::factory()->create([
        'user_id' => $employeeUser->id,
        'period_month' => Carbon::now()->format('Y-m'),
        'base_salary' => 5000000,
        'bonus' => 0,
        'deduction' => 0,
        'total_salary' => 5000000,
    ]);

    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->set('form.user_ids', [$employeeUser->id])
        ->set('form.type', SalaryAdjustmentType::DEDUCTION->value)
        ->set('form.amount', '200000')
        ->set('form.description', 'Potongan Keterlambatan')
        ->call('create')
        ->assertHasNoErrors()
        ->assertDispatched('refreshDatatable');

    $payroll->refresh();
    expect($payroll->deduction)->toBe(200000);
    expect($payroll->total_salary)->toBe(4800000);
});

it('can delete an adjustment', function () {
    $employeeUser = User::factory()->active()->create();
    Employee::factory()->create(['user_id' => $employeeUser->id, 'base_salary' => 5000000]);

    $payroll = PayrollModel::factory()->create([
        'user_id' => $employeeUser->id,
        'period_month' => Carbon::now()->format('Y-m'),
        'base_salary' => 5000000,
        'bonus' => 500000,
        'deduction' => 0,
        'total_salary' => 5500000,
    ]);

    $adjustment = PayrollAdjustment::factory()->create([
        'payroll_id' => $payroll->id,
        'type' => SalaryAdjustmentType::BONUS,
        'amount' => 500000,
    ]);

    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->call('delete', $adjustment->id)
        ->assertHasNoErrors()
        ->assertDispatched('refreshDatatable');

    $payroll->refresh();
    expect($payroll->bonus)->toBe(0);
    expect($payroll->total_salary)->toBe(5000000);

    $this->assertSoftDeleted('payroll_adjustments', ['id' => $adjustment->id]);
});

it('can export payroll as pdf', function () {
    $employeeUser = User::factory()->active()->create();
    Employee::factory()->create(['user_id' => $employeeUser->id, 'base_salary' => 5000000]);

    $payroll = PayrollModel::factory()->create([
        'user_id' => $employeeUser->id,
        'period_month' => Carbon::now()->format('Y-m'),
        'base_salary' => 5000000,
        'is_paid' => IsPaid::NOT_PAID,
    ]);

    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->call('exportPdf', $payroll)
        ->assertFileDownloaded();
});

it('cannot manage adjustment without permission', function () {
    $this->user->roles()->detach();
    $this->user->permissions()->detach();

    Livewire::actingAs($this->user)
        ->test(Payroll::class)
        ->call('create')
        ->assertForbidden();
});

it('cannot access payroll page without permission', function () {
    $this->user->roles()->detach();
    $this->user->permissions()->detach();

    $this->actingAs($this->user)
        ->get(route('studio.finance.payroll.index'))
        ->assertForbidden();
});
