<?php

namespace Tests\Feature;

use App\Models\AdminPermission;
use App\Models\AdminUser;
use App\Models\Category;
use App\Models\InventoryMovement;
use App\Models\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;

class AdminCatalogTest extends TestCase
{
    use RefreshDatabase;

    public function test_admin_with_product_permission_can_create_category(): void
    {
        $admin = $this->catalogAdmin();

        $this->actingAs($admin, 'admin')
            ->post('/admin/categories', [
                'name' => 'Beauty',
                'description' => 'Beauty and self care.',
                'is_active' => '1',
            ])
            ->assertRedirect(route('admin.categories.index'));

        $this->assertDatabaseHas('categories', [
            'name' => 'Beauty',
            'slug' => 'beauty',
            'is_active' => true,
        ]);
    }

    public function test_admin_with_product_permission_can_create_product(): void
    {
        Storage::fake('public');
        $admin = $this->catalogAdmin();
        $category = Category::query()->create([
            'name' => 'Electronics',
            'slug' => 'electronics',
            'is_active' => true,
        ]);

        $this->actingAs($admin, 'admin')
            ->get('/admin/products/create')
            ->assertOk()
            ->assertDontSee('name="rating"', false);

        $this->actingAs($admin, 'admin')
            ->post('/admin/products', [
                'category_id' => $category->id,
                'name' => 'Studio Keyboard',
                'description' => 'Mechanical keyboard for workspaces.',
                'price' => '126.50',
                'purchase_price' => '80.25',
                'discount_percent' => '10',
                'fake_discount_percent' => '5',
                'meta_title' => 'Keyboard SEO Title',
                'meta_description' => 'Keyboard SEO description.',
                'stock' => '24',
                'youtube_url' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
                'is_featured' => '1',
                'variants' => [
                    ['name' => 'Size', 'value' => 'Large', 'price' => '140.00', 'purchase_price' => '95.00', 'stock' => 6],
                ],
                'images' => [
                    UploadedFile::fake()->image('front.jpg', 800, 800),
                    UploadedFile::fake()->image('side.png', 800, 800),
                ],
                'is_active' => '1',
            ])
            ->assertRedirect(route('admin.products.index'));

        $this->assertDatabaseHas('products', [
            'category_id' => $category->id,
            'name' => 'Studio Keyboard',
            'slug' => 'studio-keyboard',
            'stock' => 24,
            'purchase_price' => '80.25',
            'discount_percent' => '10.00',
            'fake_discount_percent' => '5.00',
            'meta_title' => 'Keyboard SEO Title',
            'meta_description' => 'Keyboard SEO description.',
            'is_featured' => true,
            'youtube_url' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
        ]);

        $product = Product::query()->where('slug', 'studio-keyboard')->firstOrFail();
        $this->assertSame('0.0', $product->rating);
        $this->assertDatabaseHas('product_variants', [
            'product_id' => $product->id,
            'name' => 'Size',
            'value' => 'Large',
            'stock' => 6,
            'purchase_price' => '95.00',
        ]);
        $this->assertCount(2, $product->images);
        $this->assertDatabaseHas('inventory_movements', [
            'product_id' => $product->id,
            'product_variant_id' => null,
            'type' => InventoryMovement::TYPE_INITIAL,
            'quantity_change' => 24,
            'stock_before' => 0,
            'stock_after' => 24,
        ]);
        $this->assertDatabaseHas('inventory_movements', [
            'product_id' => $product->id,
            'type' => InventoryMovement::TYPE_INITIAL,
            'quantity_change' => 6,
            'stock_before' => 0,
            'stock_after' => 6,
        ]);
        Storage::disk('public')->assertExists($product->images[0]->path);
        Storage::disk('public')->assertExists($product->images[1]->path);
    }

    public function test_admin_can_open_product_edit_page(): void
    {
        $admin = $this->catalogAdmin();
        $category = Category::query()->create([
            'name' => 'Inactive Category',
            'slug' => 'inactive-category',
            'is_active' => false,
        ]);
        $product = Product::query()->create([
            'category_id' => $category->id,
            'name' => 'Editable Product',
            'slug' => 'editable-product',
            'price' => 99,
            'stock' => 8,
            'rating' => 4.2,
            'is_active' => true,
        ]);

        $this->actingAs($admin, 'admin')
            ->get("/admin/products/{$product->id}/edit")
            ->assertOk()
            ->assertSee('Edit Product')
            ->assertSee('Editable Product')
            ->assertSee('Inactive Category')
            ->assertDontSee('name="rating"', false);
    }

    public function test_admin_can_update_toggle_and_delete_category(): void
    {
        $admin = $this->catalogAdmin();
        $category = Category::query()->create([
            'name' => 'Old Category',
            'slug' => 'old-category',
            'description' => 'Old description',
            'is_active' => true,
        ]);

        $this->actingAs($admin, 'admin')
            ->patch("/admin/categories/{$category->id}", [
                'name' => 'Updated Category',
                'description' => 'Updated description',
            ])
            ->assertRedirect(route('admin.categories.index'));

        $this->assertDatabaseHas('categories', [
            'id' => $category->id,
            'name' => 'Updated Category',
            'slug' => 'updated-category',
            'description' => 'Updated description',
            'is_active' => false,
        ]);

        $this->actingAs($admin, 'admin')
            ->patch("/admin/categories/{$category->id}/toggle")
            ->assertSessionHas('status');

        $this->assertTrue($category->fresh()->is_active);

        $this->actingAs($admin, 'admin')
            ->delete("/admin/categories/{$category->id}")
            ->assertRedirect(route('admin.categories.index'));

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

    public function test_admin_can_update_toggle_and_delete_product(): void
    {
        Storage::fake('public');

        $admin = $this->catalogAdmin();
        $category = Category::query()->create([
            'name' => 'Electronics',
            'slug' => 'electronics',
            'is_active' => true,
        ]);
        $product = Product::query()->create([
            'category_id' => $category->id,
            'name' => 'Old Product',
            'slug' => 'old-product',
            'price' => 25,
            'stock' => 5,
            'rating' => 3.5,
            'is_active' => true,
        ]);
        $image = $product->images()->create([
            'path' => UploadedFile::fake()->image('existing.jpg')->store('products', 'public'),
            'sort_order' => 0,
        ]);

        $this->actingAs($admin, 'admin')
            ->patch("/admin/products/{$product->id}", [
                'category_id' => $category->id,
                'name' => 'Updated Product',
                'description' => 'Updated product description.',
                'price' => '49.99',
                'purchase_price' => '30.50',
                'discount_percent' => '15',
                'fake_discount_percent' => '0',
                'meta_title' => 'Updated SEO Title',
                'meta_description' => 'Updated SEO description.',
                'stock' => '12',
                'youtube_url' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
                'is_featured' => '1',
                'images' => [
                    UploadedFile::fake()->image('new.jpg', 800, 800),
                ],
            ])
            ->assertRedirect(route('admin.products.index'));

        $this->assertDatabaseHas('products', [
            'id' => $product->id,
            'name' => 'Updated Product',
            'slug' => 'updated-product',
            'stock' => 12,
            'purchase_price' => '30.50',
            'discount_percent' => '15.00',
            'fake_discount_percent' => '0.00',
            'meta_title' => 'Updated SEO Title',
            'meta_description' => 'Updated SEO description.',
            'is_featured' => true,
            'is_active' => false,
        ]);
        $this->assertSame('3.5', $product->fresh()->rating);
        $this->assertCount(2, $product->fresh()->images);
        $this->assertDatabaseHas('inventory_movements', [
            'product_id' => $product->id,
            'type' => InventoryMovement::TYPE_MANUAL_ADJUSTMENT,
            'quantity_change' => 7,
            'stock_before' => 5,
            'stock_after' => 12,
        ]);

        $this->actingAs($admin, 'admin')
            ->get(route('admin.inventory.index', ['product_id' => $product->id]))
            ->assertOk()
            ->assertSee('Inventory History')
            ->assertSee('Manual Adjustment')
            ->assertSee('+7')
            ->assertSee('Updated Product');

        $this->actingAs($admin, 'admin')
            ->patch("/admin/products/{$product->id}/toggle")
            ->assertSessionHas('status');

        $this->assertTrue($product->fresh()->is_active);

        $this->actingAs($admin, 'admin')
            ->delete("/admin/products/{$product->id}")
            ->assertRedirect(route('admin.products.index'));

        Storage::disk('public')->assertMissing($image->path);
        $this->assertDatabaseMissing('products', ['id' => $product->id]);
    }

    public function test_admin_without_product_permission_cannot_access_catalog_pages(): void
    {
        $admin = AdminUser::query()->create([
            'name' => 'Dashboard Admin',
            'email' => 'dashboard.only@example.com',
            'password' => Hash::make('secret-password'),
            'is_active' => true,
        ]);

        $permission = AdminPermission::query()->create(['name' => 'View Dashboard', 'slug' => 'dashboard.view']);
        $admin->permissions()->attach($permission);

        $this->actingAs($admin, 'admin')
            ->get('/admin/products')
            ->assertForbidden();
    }

    public function test_storefront_renders_active_database_products(): void
    {
        $category = Category::query()->create([
            'name' => 'Home',
            'slug' => 'home',
            'is_active' => true,
        ]);

        Product::query()->create([
            'category_id' => $category->id,
            'name' => 'Cotton Throw',
            'slug' => 'cotton-throw',
            'price' => 64,
            'discount_percent' => 10,
            'stock' => 19,
            'rating' => 4.6,
            'is_active' => true,
        ]);

        $this->get('/')
            ->assertOk()
            ->assertSee('Cotton Throw')
            ->assertSee('Home')
            ->assertSee('Rs 58')
            ->assertSee('Rs 64')
            ->assertSee('10% off');
    }

    public function test_storefront_has_dynamic_category_filters_without_header_search_or_dashboard_link(): void
    {
        $category = Category::query()->create([
            'name' => 'Fitness',
            'slug' => 'fitness',
            'is_active' => true,
        ]);

        Product::query()->create([
            'category_id' => $category->id,
            'name' => 'Training Kit',
            'slug' => 'training-kit',
            'price' => 72,
            'stock' => 11,
            'rating' => 4.3,
            'is_active' => true,
        ]);

        $this->get('/')
            ->assertOk()
            ->assertDontSee('data-category-filter', false)
            ->assertSee('data-hero-filter-form', false)
            ->assertSee('data-filter-search', false)
            ->assertSee('data-filter-category', false)
            ->assertDontSee('data-filter-budget', false)
            ->assertDontSee('Budget')
            ->assertSee('data-price="72"', false)
            ->assertSee('data-product-card', false)
            ->assertDontSee('Search products or categories')
            ->assertDontSee('Dashboard');
    }

    public function test_storefront_renders_product_and_category_seo_metadata(): void
    {
        Storage::fake('public');

        $categoryOg = UploadedFile::fake()->image('category-og.jpg', 1200, 630)->store('seo', 'public');
        $productOg = UploadedFile::fake()->image('product-og.jpg', 1200, 630)->store('seo', 'public');

        $category = Category::query()->create([
            'name' => 'Smart Gadgets',
            'slug' => 'smart-gadgets',
            'description' => 'Latest connected devices.',
            'meta_title' => 'Smart Gadgets Meta',
            'meta_description' => 'Shop smart gadgets with fast delivery.',
            'og_image_path' => $categoryOg,
            'is_active' => true,
        ]);

        Product::query()->create([
            'category_id' => $category->id,
            'name' => 'Smart Watch',
            'slug' => 'smart-watch',
            'description' => 'Track fitness and calls.',
            'price' => 120,
            'stock' => 15,
            'meta_title' => 'Smart Watch Meta',
            'meta_description' => 'Buy Smart Watch at 8Stores.',
            'og_image_path' => $productOg,
            'is_active' => true,
        ]);

        $this->get('/categories/smart-gadgets')
            ->assertOk()
            ->assertSee('<title>Smart Gadgets Meta</title>', false)
            ->assertSee('name="description" content="Shop smart gadgets with fast delivery."', false)
            ->assertSee("/storage/{$categoryOg}", false);

        $this->get('/products/smart-watch')
            ->assertOk()
            ->assertSee('<title>Smart Watch Meta</title>', false)
            ->assertSee('name="description" content="Buy Smart Watch at 8Stores."', false)
            ->assertSee('property="og:type" content="product"', false)
            ->assertSee("/storage/{$productOg}", false);
    }

    private function catalogAdmin(): AdminUser
    {
        $admin = AdminUser::query()->create([
            'name' => 'Catalog Admin',
            'email' => 'catalog.admin@example.com',
            'password' => Hash::make('secret-password'),
            'is_active' => true,
        ]);

        $dashboard = AdminPermission::query()->create(['name' => 'View Dashboard', 'slug' => 'dashboard.view']);
        $products = AdminPermission::query()->create(['name' => 'Manage Products', 'slug' => 'products.manage']);
        $admin->permissions()->attach([$dashboard->id, $products->id]);

        return $admin;
    }
}
