<?php

use App\Enums\IsShow;
use App\Enums\RewardCategory;
use App\Livewire\Studio\Loyalty\Reward;
use App\Models\Redemption;
use App\Models\Reward as RewardModel;
use App\Models\Tier;
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 reward']);
    Permission::firstOrCreate(['name' => 'create reward']);
    Permission::firstOrCreate(['name' => 'update reward']);
    Permission::firstOrCreate(['name' => 'delete reward']);
    $role->givePermissionTo(['view reward', 'create reward', 'update reward', 'delete reward']);
    $this->user->assignRole($role);
});

it('renders the reward page correctly', function () {
    $this->actingAs($this->user)
        ->get(route('studio.loyalty.reward.index'))
        ->assertOk()
        ->assertSeeLivewire(Reward::class);
});

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

it('shows validation errors on create', function () {
    Livewire::actingAs($this->user)
        ->test(Reward::class)
        ->call('create')
        ->assertHasErrors([
            'form.name' => 'required',
            'form.points' => 'required',
            'form.start_date' => 'required',
            'form.tier_ids' => 'required',
        ]);
});

it('can store a new reward', function () {
    $tier = Tier::factory()->create(['min_spending' => 0]);

    Livewire::actingAs($this->user)
        ->test(Reward::class)
        ->set('form.name', 'Hadiah Keren')
        ->set('form.points', '100')
        ->set('form.category', RewardCategory::REGULAR->value)
        ->set('form.is_show', IsShow::SHOW->value)
        ->set('form.start_date', now()->format('Y-m-d'))
        ->set('form.tier_ids', [$tier->id])
        ->call('create')
        ->assertHasNoErrors()
        ->assertDispatched('refreshDatatable');

    $this->assertDatabaseHas('rewards', [
        'name' => 'Hadiah Keren',
        'points' => 100,
    ]);
});

it('can open edit modal and load data', function () {
    $tier = Tier::factory()->create(['min_spending' => 0]);
    $reward = RewardModel::factory()->create(['name' => 'Old Name', 'points' => 50]);
    $reward->tiers()->attach($tier);

    Livewire::actingAs($this->user)
        ->test(Reward::class)
        ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id)
        ->set('form.reward', $reward)
        ->set('form.name', 'Old Name')
        ->set('form.points', '50')
        ->assertSet('method', 'update')
        ->assertSet('form.name', 'Old Name')
        ->assertSet('form.points', '50');
});

it('can update a reward', function () {
    $tier = Tier::factory()->create(['min_spending' => 0]);
    $reward = RewardModel::factory()->create(['name' => 'Old Name', 'points' => 50]);
    $reward->tiers()->attach($tier);

    Livewire::actingAs($this->user)
        ->test(Reward::class)
        ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id)
        ->set('form.reward', $reward)
        ->set('form.name', 'Updated Name')
        ->set('form.points', '75')
        ->set('form.category', $reward->category->value)
        ->set('form.is_show', $reward->is_show->value)
        ->set('form.start_date', $reward->start_date)
        ->set('form.tier_ids', [$tier->id])
        ->call('update')
        ->assertHasNoErrors()
        ->assertDispatched('refreshDatatable');

    $this->assertDatabaseHas('rewards', [
        'id' => $reward->id,
        'name' => 'Updated Name',
        'points' => 75,
    ]);
});

it('cannot update a reward if redemptions exist', function () {
    $reward = RewardModel::factory()->create();
    Redemption::factory()->create(['reward_id' => $reward->id]);

    Livewire::actingAs($this->user)
        ->test(Reward::class)
        ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id)
        ->set('form.reward', $reward)
        ->set('form.name', 'Attempt Update')
        ->call('update')
        ->assertHasNoErrors();

    // Verify it didn't change in DB
    $this->assertDatabaseMissing('rewards', ['id' => $reward->id, 'name' => 'Attempt Update']);
});

it('can delete a reward', function () {
    $reward = RewardModel::factory()->create();

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

    $this->assertSoftDeleted('rewards', ['id' => $reward->id]);
});

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

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