<?php

namespace Tests\Feature\Admin;

use App\Enums\UserType;
use App\Models\Asset;
use App\Models\AssetAssignment;
use App\Models\AssetCategory;
use App\Models\User;
use Carbon\Carbon;

use function Pest\Laravel\actingAs;

beforeEach(function () {
    $this->admin = User::factory()->create([
        'type' => UserType::ADMIN,
    ]);
    $this->category = AssetCategory::factory()->create([
        'name' => 'IT Equipment',
    ]);
});

test('admin can view asset list', function () {
    actingAs($this->admin)
        ->get(route('admin.assets.index'))
        ->assertStatus(200)
        ->assertInertia(fn ($page) => $page
            ->component('Admin/Assets/Index')
            ->has('assets.data')
            ->has('categories')
        );
});

test('admin can create asset', function () {
    $assetData = [
        'category_id' => $this->category->id,
        'name' => 'MacBook Pro 14',
        'serial_number' => 'MBP14-2024',
        'purchase_date' => Carbon::today()->toDateString(),
        'condition' => 'new',
        'status' => 'available',
    ];

    actingAs($this->admin)
        ->post(route('admin.assets.store'), $assetData)
        ->assertRedirect(route('admin.assets.index'))
        ->assertSessionHas('success');

    $this->assertDatabaseHas('assets', [
        'name' => 'MacBook Pro 14',
        'serial_number' => 'MBP14-2024',
    ]);
});

test('admin can view asset details', function () {
    $asset = Asset::factory()->create(['category_id' => $this->category->id]);

    actingAs($this->admin)
        ->get(route('admin.assets.show', $asset->id))
        ->assertStatus(200)
        ->assertInertia(fn ($page) => $page
            ->component('Admin/Assets/Show')
            ->has('asset')
        );
});

test('admin can assign asset to employee', function () {
    $asset = Asset::factory()->create([
        'category_id' => $this->category->id,
        'status' => 'available',
    ]);
    $employee = User::factory()->create(['type' => UserType::ADMIN]);

    actingAs($this->admin)
        ->post(route('admin.assets.assignments.store'), [
            'asset_id' => $asset->id,
            'user_id' => $employee->id,
            'assigned_at' => Carbon::now()->toDateTimeString(),
            'notes' => 'Testing assignment',
        ])
        ->assertRedirect()
        ->assertSessionHas('success');

    $this->assertDatabaseHas('assets', [
        'id' => $asset->id,
        'status' => 'assigned',
    ]);

    $this->assertDatabaseHas('asset_assignments', [
        'asset_id' => $asset->id,
        'user_id' => $employee->id,
        'returned_at' => null,
    ]);
});

test('admin can recall asset from employee', function () {
    $asset = Asset::factory()->create([
        'category_id' => $this->category->id,
        'status' => 'assigned',
    ]);
    $employee = User::factory()->create(['type' => UserType::ADMIN]);
    $assignment = $asset->assignments()->create([
        'user_id' => $employee->id,
        'assigned_at' => Carbon::now()->subDays(5),
    ]);

    actingAs($this->admin)
        ->post(route('admin.assets.assignments.return', $assignment->id), [
            'returned_at' => Carbon::now()->toDateTimeString(),
            'return_condition' => 'good',
            'notes' => 'Recalled for upgrade',
        ])
        ->assertRedirect()
        ->assertSessionHas('success');

    $this->assertDatabaseHas('assets', [
        'id' => $asset->id,
        'status' => 'available',
    ]);

    $this->assertDatabaseHas('asset_assignments', [
        'id' => $assignment->id,
        'return_condition' => 'good',
    ]);

    $this->assertNotNull($assignment->fresh()->returned_at);
});

test('admin can manage asset categories', function () {
    // View
    actingAs($this->admin)
        ->get(route('admin.assets.categories.index'))
        ->assertStatus(200)
        ->assertInertia(fn ($page) => $page
            ->component('Admin/Assets/Categories')
        );

    // Create
    actingAs($this->admin)
        ->post(route('admin.assets.categories.store'), [
            'name' => 'Furniture',
            'description' => 'Office furniture details',
        ])
        ->assertRedirect();

    $this->assertDatabaseHas('asset_categories', ['name' => 'Furniture']);

    $category = AssetCategory::where('name', 'Furniture')->first();

    // Update
    actingAs($this->admin)
        ->put(route('admin.assets.categories.update', $category->id), [
            'name' => 'Office Furniture',
        ])
        ->assertRedirect()
        ->assertSessionHasNoErrors();

    $this->assertDatabaseHas('asset_categories', ['name' => 'Office Furniture']);

    // Delete
    actingAs($this->admin)
        ->delete(route('admin.assets.categories.destroy', $category->id))
        ->assertRedirect();

    $this->assertDatabaseMissing('asset_categories', ['id' => $category->id]);
});

test('admin can create asset with employee assignment', function () {
    $employee = User::factory()->create(['type' => UserType::ADMIN]);
    $assetData = [
        'category_id' => $this->category->id,
        'name' => 'MacBook Pro 14',
        'serial_number' => 'MBP14-ASSIGN-2024',
        'purchase_date' => Carbon::today()->toDateString(),
        'condition' => 'new',
        'status' => 'available',
        'user_id' => $employee->id,
    ];

    actingAs($this->admin)
        ->post(route('admin.assets.store'), $assetData)
        ->assertRedirect(route('admin.assets.index'));

    $asset = Asset::where('serial_number', 'MBP14-ASSIGN-2024')->first();

    expect($asset->status)->toBe('assigned');
    $this->assertDatabaseHas('asset_assignments', [
        'asset_id' => $asset->id,
        'user_id' => $employee->id,
        'returned_at' => null,
    ]);
});

test('admin can update asset to change assigned employee', function () {
    $asset = Asset::factory()->create([
        'category_id' => $this->category->id,
        'status' => 'assigned',
    ]);
    $employee1 = User::factory()->create(['type' => UserType::ADMIN]);
    $employee2 = User::factory()->create(['type' => UserType::ADMIN]);

    $asset->assignments()->create([
        'user_id' => $employee1->id,
        'assigned_at' => Carbon::now()->subDays(5),
    ]);

    actingAs($this->admin)
        ->put(route('admin.assets.update', $asset->id), [
            'category_id' => $this->category->id,
            'name' => $asset->name,
            'serial_number' => $asset->serial_number,
            'purchase_date' => $asset->purchase_date->toDateString(),
            'condition' => 'good',
            'status' => 'assigned',
            'user_id' => $employee2->id,
        ])
        ->assertRedirect(route('admin.assets.index'));

    // Employee 1 assignment should be returned
    $this->assertDatabaseHas('asset_assignments', [
        'asset_id' => $asset->id,
        'user_id' => $employee1->id,
        'return_condition' => 'good',
    ]);
    $this->assertNotNull(AssetAssignment::where('asset_id', $asset->id)->where('user_id', $employee1->id)->first()->returned_at);

    // Employee 2 assignment should be created
    $this->assertDatabaseHas('asset_assignments', [
        'asset_id' => $asset->id,
        'user_id' => $employee2->id,
        'returned_at' => null,
    ]);

    expect($asset->fresh()->status)->toBe('assigned');
});

test('admin can update asset to unassign employee', function () {
    $asset = Asset::factory()->create([
        'category_id' => $this->category->id,
        'status' => 'assigned',
    ]);
    $employee = User::factory()->create(['type' => UserType::ADMIN]);

    $asset->assignments()->create([
        'user_id' => $employee->id,
        'assigned_at' => Carbon::now()->subDays(5),
    ]);

    actingAs($this->admin)
        ->put(route('admin.assets.update', $asset->id), [
            'category_id' => $this->category->id,
            'name' => $asset->name,
            'serial_number' => $asset->serial_number,
            'purchase_date' => $asset->purchase_date->toDateString(),
            'condition' => 'good',
            'status' => 'assigned',
            'user_id' => '', // Unassign
        ])
        ->assertRedirect(route('admin.assets.index'));

    // Employee assignment should be returned
    $this->assertDatabaseHas('asset_assignments', [
        'asset_id' => $asset->id,
        'user_id' => $employee->id,
    ]);
    $this->assertNotNull(AssetAssignment::where('asset_id', $asset->id)->where('user_id', $employee->id)->first()->returned_at);

    // Status should be back to available
    expect($asset->fresh()->status)->toBe('available');
});
