<?php

use App\Models\User;
use App\Models\Artwork;
use App\Models\ArtworkStats;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia;

/**
 * Helper: create an artwork without triggering observers (avoids GREATEST() SQLite issue).
 */
function studioArtwork(array $attrs = []): Artwork
{
    return Artwork::withoutEvents(fn () => Artwork::factory()->create($attrs));
}

beforeEach(function () {
    // Register GREATEST() polyfill for SQLite (used by observers on user_statistics)
    if (DB::connection()->getDriverName() === 'sqlite') {
        DB::connection()->getPdo()->sqliteCreateFunction('GREATEST', function (...$args) {
            return max($args);
        }, -1);
    }

    $this->user = User::factory()->create();
    $this->actingAs($this->user);
});

// ── Route Auth Tests ──────────────────────────────────────────────────────────

test('studio routes require authentication', function () {
    auth()->logout();

    $routes = [
        '/studio',
        '/studio/content',
        '/studio/artworks',
        '/studio/cards',
        '/studio/collections',
        '/studio/stories',
        '/studio/drafts',
        '/studio/scheduled',
        '/studio/calendar',
        '/studio/archived',
        '/studio/assets',
        '/studio/activity',
        '/studio/inbox',
        '/studio/challenges',
        '/studio/analytics',
        '/studio/growth',
        '/studio/search',
        '/studio/comments',
        '/studio/followers',
        '/studio/profile',
        '/studio/featured',
        '/studio/preferences',
        '/studio/settings',
    ];

    foreach ($routes as $route) {
        $this->get($route)->assertRedirect('/login');
    }
});

test('studio dashboard loads for authenticated user', function () {
    $this->get('/studio')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioDashboard')
            ->has('overview.active_challenges')
            ->has('overview.creator_health')
            ->has('overview.featured_status'));
});

test('studio dashboard honors saved landing page preference', function () {
    DB::table('dashboard_preferences')->insert([
        'user_id' => $this->user->id,
        'studio_preferences' => json_encode([
            'default_landing_page' => 'scheduled',
        ], JSON_THROW_ON_ERROR),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $this->get('/studio')
        ->assertRedirect('/studio/scheduled');
});

test('studio artworks page loads', function () {
    $this->get('/studio/artworks')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page->component('Studio/StudioArtworks')->where('title', 'Artworks'));
});

test('studio drafts page loads', function () {
    $this->get('/studio/artworks/drafts')
        ->assertRedirect('/studio/drafts');

    $this->get('/studio/drafts')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page->component('Studio/StudioDrafts')->where('title', 'Drafts'));
});

test('studio archived page loads', function () {
    $this->get('/studio/artworks/archived')
        ->assertRedirect('/studio/archived');

    $this->get('/studio/archived')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page->component('Studio/StudioArchived')->where('title', 'Archived'));
});

test('studio scheduled page loads', function () {
    $this->get('/studio/scheduled')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioScheduled')
            ->where('title', 'Scheduled')
            ->has('listing.items')
            ->has('listing.summary')
            ->has('listing.agenda')
            ->has('listing.range_options')
            ->where('endpoints.publishNowPattern', route('api.studio.schedule.publishNow', ['module' => '__MODULE__', 'id' => '__ID__']))
            ->where('endpoints.unschedulePattern', route('api.studio.schedule.unschedule', ['module' => '__MODULE__', 'id' => '__ID__'])));
});

test('studio calendar page loads', function () {
    $this->get('/studio/calendar')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioCalendar')
            ->where('title', 'Calendar')
            ->has('calendar.month.days')
            ->has('calendar.week.days')
            ->has('calendar.agenda')
            ->has('calendar.unscheduled_items')
            ->where('endpoints.publishNowPattern', route('api.studio.schedule.publishNow', ['module' => '__MODULE__', 'id' => '__ID__'])));
});

test('studio activity page loads', function () {
    $this->get('/studio/activity')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioActivity')
            ->where('title', 'Activity')
            ->has('listing.items')
            ->has('listing.summary')
            ->has('listing.module_options')
            ->where('endpoints.markAllRead', route('api.studio.activity.readAll')));
});

test('studio inbox page loads', function () {
    $this->get('/studio/inbox')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioInbox')
            ->where('title', 'Inbox')
            ->has('inbox.items')
            ->has('inbox.panels.attention_now')
            ->has('inbox.read_state_options')
            ->has('inbox.priority_options')
            ->where('endpoints.markAllRead', route('api.studio.activity.readAll')));
});

test('studio challenges page exposes challenge workflow payload', function () {
    $this->get('/studio/challenges')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioChallenges')
            ->where('title', 'Challenges')
            ->has('summary')
            ->has('activeChallenges')
            ->has('recentEntries')
            ->has('cardLeaders')
            ->has('reminders'));
});

test('studio search page loads', function () {
    $this->get('/studio/search')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioSearch')
            ->where('title', 'Search')
            ->has('search.filters')
            ->has('search.empty_state.continue_working')
            ->has('quickCreate'));
});

test('studio followers page loads', function () {
    $this->get('/studio/followers')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page->component('Studio/StudioFollowers')->where('title', 'Followers'));
});

test('studio assets page exposes asset library payload', function () {
    studioArtwork([
        'user_id' => $this->user->id,
    ]);

    $this->get('/studio/assets')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioAssets')
            ->where('title', 'Assets')
            ->has('assets.items')
            ->has('assets.meta')
            ->has('assets.filters')
            ->has('assets.type_options')
            ->has('assets.source_options')
            ->has('assets.sort_options')
            ->has('assets.summary')
            ->has('assets.items.0.usage_references'));
});

test('studio comments page exposes unified comments contract', function () {
    $this->get('/studio/comments')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioComments')
            ->where('title', 'Comments')
            ->has('listing.items')
            ->has('listing.meta')
            ->has('listing.filters')
            ->has('listing.module_options')
            ->where('endpoints.replyPattern', route('api.studio.comments.reply', ['module' => '__MODULE__', 'commentId' => '__COMMENT__']))
            ->where('endpoints.moderatePattern', route('api.studio.comments.moderate', ['module' => '__MODULE__', 'commentId' => '__COMMENT__']))
            ->where('endpoints.reportPattern', route('api.studio.comments.report', ['module' => '__MODULE__', 'commentId' => '__COMMENT__'])));
});

test('studio profile page exposes editable profile contract', function () {
    $this->get('/studio/profile')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioProfile')
            ->where('title', 'Profile')
            ->where('profile.name', $this->user->name)
            ->where('profile.username', $this->user->username)
            ->has('profile.social_links')
            ->has('moduleSummaries')
            ->has('featuredModules')
            ->has('featuredContent')
            ->where('endpoints.profile', route('api.studio.preferences.profile'))
            ->where('endpoints.avatarUpload', route('avatar.upload'))
            ->where('endpoints.coverUpload', route('api.profile.cover.upload'))
            ->where('endpoints.coverPosition', route('api.profile.cover.position'))
            ->where('endpoints.coverDelete', route('api.profile.cover.destroy')));
});

test('studio featured page exposes selection contract', function () {
    $this->get('/studio/featured')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioFeatured')
            ->where('title', 'Featured')
            ->has('items')
            ->has('selected')
            ->has('featuredModules')
            ->where('endpoints.save', route('api.studio.preferences.featured')));
});

test('studio preferences page exposes preference contract', function () {
    $this->get('/studio/preferences')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioPreferences')
            ->where('title', 'Preferences')
            ->has('preferences')
            ->where('preferences.default_landing_page', 'overview')
            ->has('preferences.widget_visibility')
            ->has('preferences.widget_order')
            ->has('links')
            ->where('endpoints.save', route('api.studio.preferences.settings')));
});

test('studio settings page exposes settings handoff payload', function () {
    $this->get('/studio/settings')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioSettings')
            ->where('title', 'Settings')
            ->has('links')
            ->has('sections'));
});

test('studio analytics page exposes trend and comparison payloads', function () {
    $this->get('/studio/analytics')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioAnalytics')
            ->has('totals')
            ->has('topContent')
            ->has('moduleBreakdown')
            ->has('viewsTrend')
            ->has('engagementTrend')
            ->has('publishingTimeline')
            ->has('comparison')
            ->has('insightBlocks')
            ->where('rangeDays', 30)
            ->has('recentComments'));
});

test('studio analytics page respects requested date range', function () {
    $this->get('/studio/analytics?range_days=14')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioAnalytics')
            ->where('rangeDays', 14));
});

test('studio growth page exposes growth workspace payloads', function () {
    $this->get('/studio/growth')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioGrowth')
            ->where('title', 'Growth')
            ->has('summary')
            ->has('moduleFocus')
            ->has('checkpoints')
            ->has('opportunities')
            ->has('milestones')
            ->has('momentum.views_trend')
            ->has('momentum.engagement_trend')
            ->has('momentum.publishing_timeline')
            ->where('rangeDays', 30));
});

test('studio growth page respects requested date range', function () {
    $this->get('/studio/growth?range_days=14')
        ->assertStatus(200)
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioGrowth')
            ->where('rangeDays', 14));
});

// ── API Tests ─────────────────────────────────────────────────────────────────

test('studio api requires authentication', function () {
    auth()->logout();

    $this->getJson('/api/studio/artworks')
        ->assertStatus(401);

    $this->postJson('/api/studio/events', [
        'event_type' => 'studio_opened',
    ])->assertStatus(401);
});

test('studio events api accepts known creator studio hooks', function () {
    $this->postJson('/api/studio/events', [
        'event_type' => 'studio_filter_used',
        'module' => 'artworks',
        'surface' => '/studio/artworks',
        'item_module' => 'artworks',
        'item_id' => 42,
        'meta' => [
            'filter' => 'bucket',
            'value' => 'drafts',
        ],
    ])
        ->assertStatus(202)
        ->assertJsonPath('ok', true);
});

test('studio api returns artworks for authenticated user', function () {
    // Create artworks for this user
    $artwork = studioArtwork([
        'user_id'   => $this->user->id,
        'is_public' => true,
        'is_approved' => true,
    ]);

    ArtworkStats::create([
        'artwork_id' => $artwork->id,
        'views'      => 100,
        'downloads'  => 10,
        'favorites'  => 5,
    ]);

    $this->getJson('/api/studio/artworks')
        ->assertStatus(200)
        ->assertJsonStructure([
            'data' => [['id', 'title', 'slug', 'views', 'favourites']],
            'meta' => ['current_page', 'last_page', 'per_page', 'total'],
        ]);
});

test('studio api does not return other users artworks', function () {
    $otherUser = User::factory()->create();
    studioArtwork([
        'user_id'   => $otherUser->id,
        'is_public' => true,
        'is_approved' => true,
    ]);

    $this->getJson('/api/studio/artworks')
        ->assertStatus(200)
        ->assertJsonCount(0, 'data');
});

// ── Bulk Action Tests ─────────────────────────────────────────────────────────

test('bulk archive works on owned artworks', function () {
    $artwork = studioArtwork([
        'user_id'   => $this->user->id,
        'is_public' => true,
    ]);

    $this->postJson('/api/studio/artworks/bulk', [
        'action'      => 'archive',
        'artwork_ids' => [$artwork->id],
    ])
        ->assertStatus(200)
        ->assertJsonPath('success', 1);

    expect($artwork->fresh()->trashed())->toBeTrue();
});

test('bulk delete requires confirmation', function () {
    $artwork = studioArtwork(['user_id' => $this->user->id]);

    $this->postJson('/api/studio/artworks/bulk', [
        'action'      => 'delete',
        'artwork_ids' => [$artwork->id],
    ])
        ->assertStatus(422);
});

test('bulk delete with confirmation works', function () {
    $artwork = studioArtwork(['user_id' => $this->user->id]);

    $this->postJson('/api/studio/artworks/bulk', [
        'action'      => 'delete',
        'artwork_ids' => [$artwork->id],
        'confirm'     => 'DELETE',
    ])
        ->assertStatus(200)
        ->assertJsonPath('success', 1);
});

test('bulk publish on owned artworks', function () {
    $artwork = studioArtwork([
        'user_id'   => $this->user->id,
        'is_public' => false,
    ]);

    $this->postJson('/api/studio/artworks/bulk', [
        'action'      => 'publish',
        'artwork_ids' => [$artwork->id],
    ])
        ->assertStatus(200)
        ->assertJsonPath('success', 1);

    expect($artwork->fresh()->is_public)->toBeTrue();
});

test('bulk action cannot modify other users artworks', function () {
    $otherUser = User::factory()->create();
    $artwork = studioArtwork(['user_id' => $otherUser->id]);

    $this->postJson('/api/studio/artworks/bulk', [
        'action'      => 'archive',
        'artwork_ids' => [$artwork->id],
    ])
        ->assertStatus(422)
        ->assertJsonPath('success', 0)
        ->assertJsonPath('failed', 1);
});

// ── Toggle Tests ──────────────────────────────────────────────────────────────

test('toggle publish on single artwork', function () {
    $artwork = studioArtwork([
        'user_id'   => $this->user->id,
        'is_public' => false,
    ]);

    $this->postJson("/api/studio/artworks/{$artwork->id}/toggle", [
        'action' => 'publish',
    ])
        ->assertStatus(200)
        ->assertJsonPath('success', true);

    expect($artwork->fresh()->is_public)->toBeTrue();
});

test('toggle on non-owned artwork returns 404', function () {
    $otherUser = User::factory()->create();
    $artwork = studioArtwork(['user_id' => $otherUser->id]);

    $this->postJson("/api/studio/artworks/{$artwork->id}/toggle", [
        'action' => 'archive',
    ])
        ->assertStatus(404);
});

// ── Analytics API Tests ───────────────────────────────────────────────────────

test('analytics api returns artwork stats', function () {
    $artwork = studioArtwork(['user_id' => $this->user->id]);
    ArtworkStats::create([
        'artwork_id'     => $artwork->id,
        'views'          => 500,
        'downloads'      => 20,
        'favorites'      => 30,
        'shares_count'   => 10,
        'comments_count' => 5,
        'ranking_score'  => 42.5,
        'heat_score'     => 8.3,
    ]);

    $this->getJson("/api/studio/artworks/{$artwork->id}/analytics")
        ->assertStatus(200)
        ->assertJsonStructure([
            'artwork' => ['id', 'title', 'slug'],
            'analytics' => ['views', 'favourites', 'shares', 'comments', 'downloads', 'ranking_score', 'heat_score'],
        ]);
});

test('analytics api denies access to other users artwork', function () {
    $otherUser = User::factory()->create();
    $artwork = studioArtwork(['user_id' => $otherUser->id]);

    $this->getJson("/api/studio/artworks/{$artwork->id}/analytics")
        ->assertStatus(404);
});

