<?php

declare(strict_types=1);

use App\Models\HomepageAnnouncement;
use App\Models\User;
use App\Services\HomepageAnnouncementService;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

uses(TestCase::class);

beforeEach(function (): void {
    Schema::dropIfExists('homepage_announcements');
    Schema::dropIfExists('user_profiles');
    Schema::dropIfExists('users');

    Schema::create('users', function (Blueprint $table): void {
        $table->id();
        $table->string('name')->nullable();
        $table->string('username')->nullable();
        $table->string('email')->nullable();
        $table->string('password')->nullable();
        $table->string('role')->default('user');
        $table->boolean('is_active')->default(true);
        $table->timestamps();
        $table->softDeletes();
    });

    Schema::create('homepage_announcements', function (Blueprint $table): void {
        $table->id();
        $table->string('title', 180);
        $table->string('subtitle', 255)->nullable();
        $table->string('badge_text', 100)->nullable();
        $table->longText('content_html')->nullable();
        $table->string('type', 40)->default('announcement');
        $table->string('status', 40)->default('draft');
        $table->boolean('is_active')->default(true);
        $table->dateTime('starts_at')->nullable();
        $table->dateTime('ends_at')->nullable();
        $table->string('primary_link_label', 80)->nullable();
        $table->string('primary_link_type', 40)->nullable();
        $table->string('primary_link_url', 2048)->nullable();
        $table->string('primary_link_target_type', 40)->nullable();
        $table->unsignedBigInteger('primary_link_target_id')->nullable();
        $table->string('secondary_link_label', 80)->nullable();
        $table->string('secondary_link_type', 40)->nullable();
        $table->string('secondary_link_url', 2048)->nullable();
        $table->string('secondary_link_target_type', 40)->nullable();
        $table->unsignedBigInteger('secondary_link_target_id')->nullable();
        $table->string('background_type', 40)->nullable();
        $table->string('background_image', 2048)->nullable();
        $table->string('gradient_preset', 80)->nullable();
        $table->string('theme_preset', 80)->nullable();
        $table->string('text_color', 32)->nullable();
        $table->unsignedTinyInteger('overlay_opacity')->nullable();
        $table->string('placement', 80)->default('homepage_after_featured');
        $table->integer('priority')->default(0);
        $table->boolean('is_dismissible')->default(true);
        $table->unsignedInteger('dismiss_version')->default(1);
        $table->unsignedBigInteger('created_by')->nullable();
        $table->unsignedBigInteger('updated_by')->nullable();
        $table->timestamps();
        $table->softDeletes();
    });

    Schema::create('user_profiles', function (Blueprint $table): void {
        $table->id();
        $table->unsignedBigInteger('user_id')->unique();
        $table->string('avatar_hash')->nullable();
        $table->timestamps();
    });

    app(HomepageAnnouncementService::class)->clearActiveCache();
});

afterEach(function (): void {
    Schema::dropIfExists('homepage_announcements');
    Schema::dropIfExists('user_profiles');
    Schema::dropIfExists('users');
    \Mockery::close();
});

function announcementPayload(array $overrides = []): array
{
    return array_merge([
        'title' => 'Skinbase is live.',
        'subtitle' => 'A new chapter for the Skinbase creative community.',
        'badge_text' => 'Launch Day · 1 May 2026',
        'content_html' => '<p><strong>Today, 1 May 2026, Skinbase begins a new chapter.</strong></p>',
        'type' => HomepageAnnouncement::TYPE_LAUNCH,
        'status' => HomepageAnnouncement::STATUS_PUBLISHED,
        'is_active' => true,
        'starts_at' => now()->subHour(),
        'ends_at' => null,
        'primary_link_label' => null,
        'primary_link_type' => HomepageAnnouncement::LINK_TYPE_NONE,
        'primary_link_url' => null,
        'primary_link_target_type' => null,
        'primary_link_target_id' => null,
        'secondary_link_label' => null,
        'secondary_link_type' => HomepageAnnouncement::LINK_TYPE_NONE,
        'secondary_link_url' => null,
        'secondary_link_target_type' => null,
        'secondary_link_target_id' => null,
        'background_type' => null,
        'background_image' => null,
        'gradient_preset' => HomepageAnnouncement::GRADIENT_NOVA_AURORA,
        'theme_preset' => 'launch',
        'text_color' => null,
        'overlay_opacity' => 55,
        'placement' => HomepageAnnouncement::PLACEMENT_HOMEPAGE_AFTER_FEATURED,
        'priority' => 100,
        'is_dismissible' => true,
        'dismiss_version' => 1,
    ], $overrides);
}

function createAnnouncement(array $overrides = []): HomepageAnnouncement
{
    return HomepageAnnouncement::query()->create(announcementPayload($overrides));
}

function adminUser(): User
{
    return User::query()->create([
        'name' => 'Admin User',
        'username' => 'adminuser',
        'email' => 'admin@example.com',
        'password' => Hash::make('password'),
        'role' => 'admin',
        'is_active' => true,
    ]);
}

it('returns the visible published active homepage announcement', function (): void {
    $expected = createAnnouncement();

    $active = app(HomepageAnnouncementService::class)->getActiveForHomepage();

    expect($active?->id)->toBe($expected->id);
});

it('does not return a future announcement', function (): void {
    createAnnouncement([
        'starts_at' => now()->addHour(),
    ]);

    expect(app(HomepageAnnouncementService::class)->getActiveForHomepage())->toBeNull();
});

it('does not return an expired announcement', function (): void {
    createAnnouncement([
        'starts_at' => now()->subDays(2),
        'ends_at' => now()->subMinute(),
    ]);

    expect(app(HomepageAnnouncementService::class)->getActiveForHomepage())->toBeNull();
});

it('does not return a draft announcement', function (): void {
    createAnnouncement([
        'status' => HomepageAnnouncement::STATUS_DRAFT,
    ]);

    expect(app(HomepageAnnouncementService::class)->getActiveForHomepage())->toBeNull();
});

it('returns the highest priority visible announcement', function (): void {
    createAnnouncement([
        'priority' => 10,
        'title' => 'Lower priority',
    ]);

    $higher = createAnnouncement([
        'priority' => 900,
        'title' => 'Higher priority',
    ]);

    $active = app(HomepageAnnouncementService::class)->getActiveForHomepage();

    expect($active?->id)->toBe($higher->id);
});

it('homepage payload includes the announcement prop', function (): void {
    $html = view('web.home', [
        'seo' => [],
        'useUnifiedSeo' => true,
        'meta' => [],
        'props' => [
            'hero' => [],
            'announcement' => [
                'id' => 42,
                'dismiss_version' => 1,
                'title' => 'Skinbase is live.',
                'subtitle' => 'A new chapter.',
                'badge_text' => 'Launch',
                'content_html' => '<p>Hello</p>',
                'gradient_preset' => 'nova_aurora',
                'theme_preset' => 'launch',
                'background_image_url' => null,
                'is_dismissible' => true,
                'overlay_opacity' => 55,
                'primary_link' => null,
                'secondary_link' => null,
            ],
            'community_favorites' => [],
            'hall_of_fame' => [],
            'rising' => [],
            'trending' => [],
            'fresh' => [],
            'collections_featured' => [],
            'collections_trending' => [],
            'collections_editorial' => [],
            'collections_community' => [],
            'world_spotlight' => null,
            'groups' => [],
            'tags' => [],
            'creators' => [],
            'news' => [],
        ],
    ])->render();

    expect($html)->toContain('"announcement":{"id":42');
});

it('homepage renders stable intro copy and excludes footer utility text from snippets', function (): void {
    $html = view('web.home', [
        'seo' => [],
        'useUnifiedSeo' => true,
        'meta' => [],
        'props' => [
            'hero' => [
                'title' => 'Featured Example',
                'author' => 'CreatorName',
                'url' => '/art/1/featured-example',
            ],
            'announcement' => null,
            'community_favorites' => [],
            'hall_of_fame' => [],
            'rising' => [],
            'trending' => [],
            'fresh' => [],
            'collections_featured' => [],
            'collections_trending' => [],
            'collections_editorial' => [],
            'collections_community' => [],
            'world_spotlight' => null,
            'groups' => [],
            'tags' => [],
            'creators' => [],
            'news' => [],
        ],
    ])->render();

    expect($html)
        ->toContain('Discover digital art, wallpapers, skins, and photography from a global creator community.')
        ->toContain('data-nosnippet');
});

it('preview sanitizes html content', function (): void {
    $admin = adminUser();

    $this->withoutMiddleware(\App\Http\Middleware\HandleInertiaRequests::class);

    $response = $this->actingAs($admin)->post(route('admin.homepage-announcements.preview'), [
        'title' => 'Preview announcement',
        'subtitle' => 'Unsafe html should be stripped.',
        'badge_text' => 'Preview',
        'content_html' => '<p>Hello<script>alert(1)</script></p><a href="https://skinbase.org" onclick="evil()">Visit</a>',
        'type' => HomepageAnnouncement::TYPE_NOTICE,
        'status' => HomepageAnnouncement::STATUS_PUBLISHED,
        'is_active' => true,
        'starts_at' => now()->toIso8601String(),
        'priority' => 10,
        'is_dismissible' => true,
        'dismiss_version' => 1,
        'gradient_preset' => HomepageAnnouncement::GRADIENT_NOVA_AURORA,
        'theme_preset' => 'announcement',
        'placement' => HomepageAnnouncement::PLACEMENT_HOMEPAGE_AFTER_FEATURED,
        'overlay_opacity' => 55,
        'primary_link_type' => HomepageAnnouncement::LINK_TYPE_CUSTOM_URL,
        'primary_link_label' => 'Open',
        'primary_link_url' => '/explore',
        'secondary_link_type' => HomepageAnnouncement::LINK_TYPE_NONE,
    ]);

    $response
        ->assertOk()
        ->assertJsonPath('announcement.content_html', '<p>Hello</p><a href="https://skinbase.org" rel="noopener noreferrer" target="_blank">Visit</a>');
});

it('preview rejects unsafe custom links', function (): void {
    $admin = adminUser();

    $this->withoutMiddleware(\App\Http\Middleware\HandleInertiaRequests::class);

    $this->actingAs($admin)
        ->from(route('admin.homepage-announcements.create'))
        ->post(route('admin.homepage-announcements.preview'), [
            'title' => 'Unsafe CTA',
            'type' => HomepageAnnouncement::TYPE_NOTICE,
            'status' => HomepageAnnouncement::STATUS_PUBLISHED,
            'is_active' => true,
            'priority' => 0,
            'is_dismissible' => true,
            'dismiss_version' => 1,
            'gradient_preset' => HomepageAnnouncement::GRADIENT_NOVA_AURORA,
            'theme_preset' => 'announcement',
            'placement' => HomepageAnnouncement::PLACEMENT_HOMEPAGE_AFTER_FEATURED,
            'overlay_opacity' => 55,
            'primary_link_type' => HomepageAnnouncement::LINK_TYPE_CUSTOM_URL,
            'primary_link_label' => 'Do not allow',
            'primary_link_url' => 'javascript:alert(1)',
            'secondary_link_type' => HomepageAnnouncement::LINK_TYPE_NONE,
        ])
        ->assertSessionHasErrors(['primary_link_url']);
});

it('stores announcement background uploads on the configured object storage disk', function (): void {
    $admin = adminUser();

    Storage::fake('s3');
    config([
        'homepage.announcements.background_image.disk' => 's3',
        'homepage.announcements.background_image.prefix' => 'homepage-announcements',
        'filesystems.disks.s3.url' => 'https://cdn.skinbase.test',
    ]);

    $this->withoutMiddleware(\App\Http\Middleware\HandleInertiaRequests::class);

    $response = $this->actingAs($admin)
        ->from(route('admin.homepage-announcements.create'))
        ->post(route('admin.homepage-announcements.store'), array_merge(announcementPayload(), [
            'background_image_file' => UploadedFile::fake()->image('announcement.png', 1600, 900),
        ]));

    $response->assertRedirect();

    $announcement = HomepageAnnouncement::query()->latest('id')->firstOrFail();

    expect($announcement->background_image)
        ->toStartWith('homepage-announcements/')
        ->toEndWith('.webp');

    Storage::disk('s3')->assertExists($announcement->background_image);

    $payload = app(HomepageAnnouncementService::class)->toHomepagePayload($announcement);

    expect($payload['background_image_url'])
        ->toBe('https://cdn.skinbase.test/' . $announcement->background_image);
});