<?php

declare(strict_types=1);

use App\Models\Artwork;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use Illuminate\Foundation\Vite as LaravelVite;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\File;

uses(RefreshDatabase::class);

$originalManifest = null;

beforeEach(function () use (&$originalManifest): void {
    File::ensureDirectoryExists(public_path('build'));

    $manifestPath = public_path('build/manifest.json');
    $originalManifest = File::exists($manifestPath)
        ? File::get($manifestPath)
        : null;

    app()->forgetInstance(LaravelVite::class);
});

afterEach(function () use (&$originalManifest): void {
    $manifestPath = public_path('build/manifest.json');

    if ($originalManifest === null) {
        File::delete($manifestPath);

        app()->forgetInstance(LaravelVite::class);

        return;
    }

    File::put($manifestPath, $originalManifest);
    app()->forgetInstance(LaravelVite::class);
});

it('renders the nova error layout when stylesheet manifest entries do not include src', function () use (&$originalManifest): void {
    expect($originalManifest)->not->toBeNull();

    $manifest = json_decode($originalManifest, true, 512, JSON_THROW_ON_ERROR);
    unset($manifest['resources/css/app.css']['src']);
    unset($manifest['resources/css/nova-grid.css']['src']);
    unset($manifest['resources/scss/nova.scss']['src']);

    File::put(public_path('build/manifest.json'), json_encode($manifest, JSON_THROW_ON_ERROR));
    app()->forgetInstance(LaravelVite::class);

    $vite = app(LaravelVite::class);

    $this->view('errors.500', [
        'correlationId' => 'TEST-CORRELATION-ID',
    ])
        ->assertSee($vite->asset('resources/css/app.css'), false)
        ->assertSee($vite->asset('resources/css/nova-grid.css'), false)
        ->assertSee($vite->asset('resources/scss/nova.scss'), false);
});

it('renders the similar artworks page when stylesheet manifest entries do not include src', function () use (&$originalManifest): void {
    expect($originalManifest)->not->toBeNull();

    $manifest = json_decode($originalManifest, true, 512, JSON_THROW_ON_ERROR);
    unset($manifest['resources/css/app.css']['src']);
    unset($manifest['resources/css/nova-grid.css']['src']);
    unset($manifest['resources/scss/nova.scss']['src']);

    File::put(public_path('build/manifest.json'), json_encode($manifest, JSON_THROW_ON_ERROR));
    app()->forgetInstance(LaravelVite::class);

    $vite = app(LaravelVite::class);

    $author = User::factory()->create([
        'username' => 'similarmanifestauthor',
    ]);

    $contentType = ContentType::query()->create([
        'name' => 'Skins',
        'slug' => 'skins',
        'description' => 'Skins content type',
    ]);

    $category = Category::query()->create([
        'content_type_id' => $contentType->id,
        'name' => 'Internet',
        'slug' => 'internet',
        'description' => 'Internet skins',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($author)->create([
        'title' => 'Similar Manifest Artwork',
        'slug' => 'similar-manifest-artwork',
        'published_at' => now()->subHour(),
        'is_public' => true,
        'is_approved' => true,
    ]);

    $artwork->categories()->attach($category->id);

    $this->get(route('art.similar', ['id' => $artwork->id]))
        ->assertOk()
        ->assertSee('Similar Artworks')
        ->assertSee($vite->asset('resources/css/app.css'), false)
        ->assertSee($vite->asset('resources/css/nova-grid.css'), false)
        ->assertSee($vite->asset('resources/scss/nova.scss'), false);
});

it('renders the profile page when the manifest does not contain profile.jsx', function () use (&$originalManifest): void {
    expect($originalManifest)->not->toBeNull();

    $manifest = json_decode($originalManifest, true, 512, JSON_THROW_ON_ERROR);
    unset($manifest['resources/js/profile.jsx']);

    File::put(public_path('build/manifest.json'), json_encode($manifest, JSON_THROW_ON_ERROR));
    app()->forgetInstance(LaravelVite::class);

    $vite = app(LaravelVite::class);

    $user = User::factory()->create([
        'username' => 'profilemanifestuser',
    ]);

    $this->get(route('profile.show', ['username' => strtolower((string) $user->username)]))
        ->assertOk()
        ->assertSee($vite->asset('resources/js/collections.jsx'), false);
});

it('renders the latest comments page when the manifest does not contain the community activity bundle', function () use (&$originalManifest): void {
    expect($originalManifest)->not->toBeNull();

    $manifest = json_decode($originalManifest, true, 512, JSON_THROW_ON_ERROR);
    unset($manifest['resources/js/Pages/Community/CommunityActivityPage.jsx']);

    File::put(public_path('build/manifest.json'), json_encode($manifest, JSON_THROW_ON_ERROR));
    app()->forgetInstance(LaravelVite::class);

    $this->get('/latest-comments')
        ->assertOk()
        ->assertSee('Latest Comments');
});