<?php

declare(strict_types=1);

use Builder\Core\Foundation\Auth\AuthenticationProvider;
use Builder\Core\Foundation\Concerns\HasBuilderAccess;
use Builder\Core\Foundation\Contracts\BuilderAccessible;
use Builder\Core\Foundation\Dashboard\Widgets\CounterWidget;
use Builder\Core\Foundation\Dashboard\Widgets\Widget;
use Builder\Core\Foundation\Registry;
use Builder\Core\Tests\BuilderTestUser;
use Illuminate\Foundation\Auth\User;
use Illuminate\Support\Facades\Schema;
use Inertia\Testing\AssertableInertia;

final class DashboardTestAuthProvider implements AuthenticationProvider
{
    public function identifier(): string
    {
        return 'test-oauth';
    }

    public function label(): string
    {
        return 'Test OAuth';
    }

    public function redirectRoute(): string
    {
        return 'builder.login';
    }

    public function icon(): ?string
    {
        return null;
    }
}

beforeEach(function (): void {
    Schema::create('users', function ($table): void {
        $table->id();
        $table->string('name')->nullable();
        $table->string('email')->nullable();
        $table->string('password')->nullable();
        $table->json('widget_preferences')->nullable();
        $table->timestamps();
    });
});

it('redirects unauthenticated user from dashboard', function (): void {
    $this->get(route('builder.dashboard'))
        ->assertRedirect(route('builder.login'));
});

it('renders dashboard for authenticated builder user', function (): void {
    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'secret']);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->component('Dashboard')
            ->has('widgets')
            ->has('hiddenWidgetKeys'),
        );
});

it('passes registered widgets to the dashboard', function (): void {
    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'secret']);

    app(Registry::class)->widget(
        new CounterWidget('total-items', 'Total Items', fn () => 99),
    );

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->component('Dashboard')
            ->where('widgets.0.key', 'total-items')
            ->where('widgets.0.data.value', 99),
        );
});

it('widgets are sorted by order', function (): void {
    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'secret']);

    $registry = app(Registry::class);

    $wB = new class('b') extends Widget
    {
        public function __construct(private readonly string $k)
        {
            $this->order = 2;
        }

        public function getKey(): string
        {
            return $this->k;
        }

        public function getLabel(): string
        {
            return $this->k;
        }

        public function getComponent(): string
        {
            return 'CounterWidget';
        }

        /** @return array<string, mixed> */
        public function getData(): array
        {
            return [];
        }
    };
    $wA = new class('a') extends Widget
    {
        public function __construct(private readonly string $k)
        {
            $this->order = 1;
        }

        public function getKey(): string
        {
            return $this->k;
        }

        public function getLabel(): string
        {
            return $this->k;
        }

        public function getComponent(): string
        {
            return 'CounterWidget';
        }

        /** @return array<string, mixed> */
        public function getData(): array
        {
            return [];
        }
    };

    $registry->widget($wB);
    $registry->widget($wA);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->where('widgets.0.key', 'a')
            ->where('widgets.1.key', 'b'),
        );
});

it('passes hiddenWidgetKeys from user preferences to frontend', function (): void {
    // Controller now sends ALL permission-filtered widgets + hiddenWidgetKeys for client-side filtering
    $user = BuilderTestUser::create([
        'name' => 'Admin',
        'email' => 'admin@example.com',
        'password' => 'secret',
        'widget_preferences' => json_encode(['hidden_widgets' => ['system-info', 'total-items']]),
    ]);

    app(Registry::class)->widget(new CounterWidget('total-items', 'Total Items', fn () => 10));
    app(Registry::class)->widget(new CounterWidget('other-widget', 'Other Widget', fn () => 5));

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->has('widgets', 3) // system-info + total-items + other-widget (all permission-filtered, not preference-filtered)
            ->where('hiddenWidgetKeys', ['system-info', 'total-items']),
        );
});

it('permission-gated widgets are excluded when user lacks permission', function (): void {
    $restrictedUser = new class extends User implements BuilderAccessible
    {
        use HasBuilderAccess;

        protected $table = 'users';

        protected $guarded = [];

        /** @return list<string> */
        public function builderPermissions(): array
        {
            return ['view-dashboard'];
        }
    };
    $restrictedUser->forceFill(['name' => 'Restricted', 'email' => 'r@example.com', 'password' => 'secret'])->save();

    $gatedWidget = new class('secret-stats', 'Secret Stats', fn () => 0) extends CounterWidget
    {
        protected ?string $permissionRequired = 'view-secret-stats';
    };

    app(Registry::class)->widget($gatedWidget);
    app(Registry::class)->widget(new CounterWidget('public-widget', 'Public Widget', fn () => 1));

    // system-info (no perm) + public-widget (no perm) = 2 visible; secret-stats gated
    $response = $this->actingAs($restrictedUser)
        ->get(route('builder.dashboard'));

    $response->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
        ->component('Dashboard')
        ->has('widgets'),
    );

    $widgetKeys = array_column($response->original->getData()['page']['props']['widgets'], 'key');
    expect($widgetKeys)->not->toContain('secret-stats')
        ->and($widgetKeys)->toContain('public-widget');
});

it('registered translation namespaces are included in shared translations', function (): void {
    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'trans-ns@example.com', 'password' => 'secret']);

    app(Registry::class)->translationNamespace('builder_extra', 'builder::builder');

    $response = $this->actingAs($user)
        ->get(route('builder.dashboard'));

    $translations = $response->viewData('page')['props']['translations'] ?? [];

    expect($translations)->toHaveKey('builder_extra');
});

it('hide route sets widget as hidden and returns 204', function (): void {
    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'secret']);

    $this->actingAs($user)
        ->post(route('builder.dashboard.widget.hide', ['key' => 'system-info']))
        ->assertNoContent();

    $user->refresh();
    expect($user->hiddenWidgets())->toContain('system-info');
});

it('show route removes widget from hidden and returns 204', function (): void {
    $user = BuilderTestUser::create([
        'name' => 'Admin',
        'email' => 'admin@example.com',
        'password' => 'secret',
        'widget_preferences' => json_encode(['hidden_widgets' => ['system-info']]),
    ]);

    $this->actingAs($user)
        ->post(route('builder.dashboard.widget.show', ['key' => 'system-info']))
        ->assertNoContent();

    $user->refresh();
    expect($user->hiddenWidgets())->not->toContain('system-info');
});

it('seoSettings prop is shared when builder.seo is bound', function (): void {
    $seoStub = new class
    {
        public string $site_name = 'Acme';

        public string $separator = ' | ';

        public ?string $favicon_url = 'https://acme.example/favicon.ico';
    };

    app()->bind('builder.seo', fn (): bool => true);
    app()->bind('Builder\Seo\Settings\SeoSettings', fn (): object => $seoStub);

    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'seo-test@example.com', 'password' => 'secret']);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->where('seoSettings.site_name', 'Acme')
            ->where('seoSettings.separator', ' | ')
            ->where('seoSettings.favicon_url', 'https://acme.example/favicon.ico'),
        );
});

it('socialProviders prop includes registered auth providers', function (): void {
    app(Registry::class)->authProvider(DashboardTestAuthProvider::class);

    $user = BuilderTestUser::create(['name' => 'Admin', 'email' => 'social-test@example.com', 'password' => 'secret']);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page
            ->has('auth.socialProviders', 1)
            ->where('auth.socialProviders.0.identifier', 'test-oauth')
            ->where('auth.socialProviders.0.label', 'Test OAuth'),
        );
});
