<?php

namespace Tests\Feature;

use App\Models\Brand;
use App\Models\Category;
use App\Models\Product;
use App\Models\ShippingMethod;
use App\Models\Unit;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AdminCrudTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Test administrator login.
     */
    public function test_administrator_login(): void
    {
        $admin = User::factory()->create([
            'email' => 'admin@example.com',
            'role' => 'admin',
            'password' => bcrypt('password123'),
        ]);

        $response = $this->post('/admin/login', [
            'email' => 'admin@example.com',
            'password' => 'password123',
        ]);

        $response->assertRedirect(route('admin.dashboard'));
        $this->assertAuthenticatedAs($admin);
    }

    /**
     * Test module permissions protect navigation routes.
     */
    public function test_module_permissions_protect_navigation_routes(): void
    {
        $admin = User::factory()->create([
            'role' => 'admin',
            'permissions' => ['dashboard'], // Only has dashboard permission
        ]);

        // Dashboard is accessible
        $this->actingAs($admin)->get(route('admin.dashboard'))->assertOk();

        // Products are forbidden
        $this->actingAs($admin)->get(route('admin.products.index'))->assertForbidden();
    }

    /**
     * Test product CRUD operations (Store, Edit, Update, Duplicate, and Delete).
     */
    public function test_product_crud(): void
    {
        $admin = User::factory()->create(['role' => 'admin', 'permissions' => null]);
        $category = Category::factory()->create(['name' => 'Bedding', 'slug' => 'bedding', 'code' => 'bedding']);
        $brand = Brand::create(['name' => 'Monica', 'slug' => 'monica']);
        $unit = Unit::create(['name' => 'Piece', 'abbreviation' => 'pcs']);

        // 1. Create/Store
        $response = $this->actingAs($admin)->post(route('admin.products.store'), [
            'name' => 'Monica Bed Sheet',
            'price' => 29.99,
            'category_id' => $category->id,
            'brand_id' => $brand->id,
            'unit_id' => $unit->id,
            'in_stock' => 1,
        ]);

        $response->assertRedirect(route('admin.products.index'));
        $this->assertDatabaseHas('products', [
            'name' => 'Monica Bed Sheet',
            'price' => 29.99,
            'category_id' => $category->id,
            'brand_id' => $brand->id,
            'unit_id' => $unit->id,
        ]);

        $product = Product::first();

        // 2. Edit Page View
        $this->actingAs($admin)->get(route('admin.products.edit', $product))
            ->assertOk()
            ->assertViewHasAll(['product', 'categories', 'brands', 'units']);

        // 3. Update
        $this->actingAs($admin)->put(route('admin.products.update', $product), [
            'name' => 'Monica Bed Sheet Premium',
            'price' => 39.99,
            'category_id' => $category->id,
            'brand_id' => $brand->id,
            'unit_id' => $unit->id,
            'in_stock' => 1,
            'on_sale' => 1,
        ])->assertRedirect(route('admin.products.index'));

        $this->assertDatabaseHas('products', [
            'id' => $product->id,
            'name' => 'Monica Bed Sheet Premium',
            'price' => 39.99,
            'on_sale' => true,
        ]);

        // 4. Duplicate Page View
        $this->actingAs($admin)->get(route('admin.products.duplicate', $product))
            ->assertOk()
            ->assertViewHasAll(['duplicateProduct', 'categories', 'brands', 'units']);

        // 5. Destroy/Delete
        $this->actingAs($admin)->delete(route('admin.products.destroy', $product))
            ->assertRedirect(route('admin.products.index'));

        $this->assertDatabaseMissing('products', [
            'id' => $product->id,
        ]);
    }

    /**
     * Test shipping method CRUD.
     */
    public function test_shipping_method_crud(): void
    {
        $admin = User::factory()->create(['role' => 'admin', 'permissions' => null]);

        // Create
        $response = $this->actingAs($admin)->post(route('admin.shipping-methods.store'), [
            'name' => 'Standard Delivery',
            'code' => 'standard_delivery',
            'fixed_fee' => 3.50,
            'is_active' => 1,
            'sort_order' => 10,
        ]);

        $response->assertRedirect(route('admin.shipping-methods.index'));
        $this->assertDatabaseHas('shipping_methods', [
            'name' => 'Standard Delivery',
            'code' => 'standard_delivery',
            'fixed_fee' => 3.50,
        ]);

        $method = ShippingMethod::first();

        // Update
        $this->actingAs($admin)->put(route('admin.shipping-methods.update', $method), [
            'name' => 'Standard Delivery Express',
            'code' => 'standard_delivery',
            'fixed_fee' => 5.00,
            'is_active' => 1,
            'sort_order' => 10,
        ])->assertRedirect(route('admin.shipping-methods.index'));

        $this->assertDatabaseHas('shipping_methods', [
            'id' => $method->id,
            'name' => 'Standard Delivery Express',
            'fixed_fee' => 5.00,
        ]);

        // Delete
        $this->actingAs($admin)->delete(route('admin.shipping-methods.destroy', $method))
            ->assertRedirect(route('admin.shipping-methods.index'));

        $this->assertSoftDeleted('shipping_methods', [
            'id' => $method->id,
        ]);
    }

    /**
     * Test brand CRUD.
     */
    public function test_brand_crud(): void
    {
        $admin = User::factory()->create(['role' => 'admin', 'permissions' => null]);

        // Create
        $response = $this->actingAs($admin)->post(route('admin.brands.store'), [
            'name' => 'Test Brand',
            'slug' => 'test-brand',
            'description' => 'Brand description',
            'is_featured' => 1,
            'is_active' => 1,
            'sort_order' => 5,
        ]);

        $response->assertRedirect(route('admin.brands.index'));
        $this->assertDatabaseHas('brands', [
            'name' => 'Test Brand',
            'slug' => 'test-brand',
            'is_featured' => true,
        ]);

        $brand = Brand::first();

        // Update
        $this->actingAs($admin)->put(route('admin.brands.update', $brand), [
            'name' => 'Test Brand Updated',
            'slug' => 'test-brand',
            'is_featured' => 0,
            'is_active' => 1,
        ])->assertRedirect(route('admin.brands.index'));

        $this->assertDatabaseHas('brands', [
            'id' => $brand->id,
            'name' => 'Test Brand Updated',
            'is_featured' => false,
        ]);

        // Delete
        $this->actingAs($admin)->delete(route('admin.brands.destroy', $brand))
            ->assertRedirect(route('admin.brands.index'));

        $this->assertSoftDeleted('brands', [
            'id' => $brand->id,
        ]);
    }

    /**
     * Test unit CRUD.
     */
    public function test_unit_crud(): void
    {
        $admin = User::factory()->create(['role' => 'admin', 'permissions' => null]);

        // Create
        $response = $this->actingAs($admin)->post(route('admin.units.store'), [
            'name' => 'Kilogram',
            'abbreviation' => 'kg',
            'description' => 'Weight unit',
            'is_active' => 1,
        ]);

        $response->assertRedirect(route('admin.units.index'));
        $this->assertDatabaseHas('units', [
            'name' => 'Kilogram',
            'abbreviation' => 'kg',
        ]);

        $unit = Unit::first();

        // Update
        $this->actingAs($admin)->put(route('admin.units.update', $unit), [
            'name' => 'Gram',
            'abbreviation' => 'g',
            'is_active' => 1,
        ])->assertRedirect(route('admin.units.index'));

        $this->assertDatabaseHas('units', [
            'id' => $unit->id,
            'name' => 'Gram',
            'abbreviation' => 'g',
        ]);

        // Delete
        $this->actingAs($admin)->delete(route('admin.units.destroy', $unit))
            ->assertRedirect(route('admin.units.index'));

        $this->assertDatabaseMissing('units', [
            'id' => $unit->id,
        ]);
    }
}
