<?php

use App\Domains\Link\Models\Link;
use App\Domains\Workspace\Models\Workspace;
use App\Domains\Workspace\Models\WorkspaceMember;
use App\Livewire\Modals\CreateLink;
use App\Livewire\Modals\DeleteLink;
use App\Livewire\Modals\EditLink;
use App\Models\User;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Livewire\Livewire;

function makeUserWithWs(): array
{
    $user = User::factory()->create();
    $ws = Workspace::factory()->create(['owner_id' => $user->id]);
    WorkspaceMember::create([
        'workspace_id' => $ws->id,
        'user_id' => $user->id,
        'role' => 'owner',
        'joined_at' => now(),
    ]);

    return [$user, $ws];
}

// CreateLink

it('renders create link modal', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    Livewire::actingAs($user)->test(CreateLink::class)
        ->assertOk()
        ->assertSee('Create Short Link');
});

it('validates required url on create link', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    Livewire::actingAs($user)->test(CreateLink::class)
        ->call('save')
        ->assertHasErrors(['targetUrl' => 'required']);
});

it('validates url format on create link', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    Livewire::actingAs($user)->test(CreateLink::class)
        ->set('targetUrl', 'not-a-url')
        ->call('save')
        ->assertHasErrors(['targetUrl']);
});

it('creates link and dispatches linkCreated', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    Livewire::actingAs($user)->test(CreateLink::class)
        ->set('targetUrl', 'https://example.com/page')
        ->call('save')
        ->assertDispatched('link-created');

    expect(Link::where('workspace_id', $ws->id)->where('target_url', 'https://example.com/page')->exists())->toBeTrue();
});

it('generate slug fills slug field when empty', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $component = Livewire::actingAs($user)->test(CreateLink::class)
        ->call('generateSlug');

    expect($component->get('slug'))->not->toBeEmpty();
});

// EditLink

it('renders edit link modal with prefilled data', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $link = Link::factory()->create([
        'workspace_id' => $ws->id,
        'title' => 'My Link',
        'slug' => 'mylink',
        'target_url' => 'https://old.example.com',
    ]);

    Livewire::actingAs($user)->test(EditLink::class, ['linkUlid' => $link->ulid])
        ->assertOk()
        ->assertSet('targetUrl', 'https://old.example.com')
        ->assertSet('slug', 'mylink');
});

it('updates link on save', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $link = Link::factory()->create([
        'workspace_id' => $ws->id,
        'slug' => 'oldslug',
        'target_url' => 'https://old.example.com',
    ]);

    Livewire::actingAs($user)->test(EditLink::class, ['linkUlid' => $link->ulid])
        ->set('targetUrl', 'https://new.example.com')
        ->set('slug', 'newslug')
        ->call('save')
        ->assertDispatched('link-updated');

    expect($link->fresh()->target_url)->toBe('https://new.example.com');
    expect($link->fresh()->slug)->toBe('newslug');
});

it('rejects edit for link in different workspace', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $otherOwner = User::factory()->create();
    $otherWs = Workspace::factory()->create(['owner_id' => $otherOwner->id]);
    $link = Link::factory()->create(['workspace_id' => $otherWs->id]);

    expect(fn () => Livewire::actingAs($user)->test(EditLink::class, ['linkUlid' => $link->ulid]))
        ->toThrow(ModelNotFoundException::class);
});

// DeleteLink

it('renders delete link modal', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $link = Link::factory()->create([
        'workspace_id' => $ws->id,
        'title' => 'My Link',
    ]);

    Livewire::actingAs($user)->test(DeleteLink::class, ['linkUlid' => $link->ulid])
        ->assertOk()
        ->assertSee('Delete Link');
});

it('soft-deletes link and dispatches linkDeleted', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $link = Link::factory()->create(['workspace_id' => $ws->id]);

    Livewire::actingAs($user)->test(DeleteLink::class, ['linkUlid' => $link->ulid])
        ->call('delete')
        ->assertDispatched('link-deleted');

    expect(Link::withTrashed()->find($link->id)->deleted_at)->not->toBeNull();
});

it('rejects delete for link in different workspace', function () {
    [$user, $ws] = makeUserWithWs();
    app()->instance('current_workspace', $ws);

    $otherOwner = User::factory()->create();
    $otherWs = Workspace::factory()->create(['owner_id' => $otherOwner->id]);
    $link = Link::factory()->create(['workspace_id' => $otherWs->id]);

    expect(fn () => Livewire::actingAs($user)->test(DeleteLink::class, ['linkUlid' => $link->ulid]))
        ->toThrow(ModelNotFoundException::class);
});
