<?php

namespace Tests\Feature;

use App\Models\GameAccountUser;
use App\Services\AzerothCoreAccountService;
use App\Services\GameClientDownloadService;
use Illuminate\Support\Collection;
use Mockery\MockInterface;
use Tests\TestCase;

class CabinetFeatureTest extends TestCase
{
    public function test_guest_is_redirected_to_login_for_cabinet(): void
    {
        $response = $this->get(route('cabinet.index'));

        $response->assertRedirect(route('login'));
    }

    public function test_authenticated_user_can_open_cabinet(): void
    {
        $user = $this->makeUser();

        $this->mock(AzerothCoreAccountService::class, function (MockInterface $mock) use ($user): void {
            $mock->shouldReceive('charactersForAccount')
                ->once()
                ->with($user->id)
                ->andReturn(new Collection([
                    [
                        'name' => 'Arthion',
                        'race' => 'Человек',
                        'class' => 'Паладин',
                        'gender' => 'Мужской',
                        'level' => 80,
                        'money' => '125з 0с 0м',
                        'played' => '4д 6ч',
                        'online' => false,
                    ],
                ]));
        });

        $response = $this->actingAs($user)->get(route('cabinet.index'));

        $response->assertOk();
        $response->assertSee('Arthion');
        $response->assertSee('Получить ссылку на клиент');
    }

    public function test_authenticated_user_can_change_password(): void
    {
        $user = $this->makeUser();

        $this->mock(AzerothCoreAccountService::class, function (MockInterface $mock) use ($user): void {
            $mock->shouldReceive('validatePassword')
                ->once()
                ->with($user, 'OldPass123')
                ->andReturn(true);

            $mock->shouldReceive('updatePassword')
                ->once()
                ->with($user, 'NewPass123');
        });

        $response = $this->actingAs($user)->post(route('cabinet.password.update'), [
            'current_password' => 'OldPass123',
            'password' => 'NewPass123',
            'password_confirmation' => 'NewPass123',
        ]);

        $response->assertRedirect();
        $response->assertSessionHas('status', 'Пароль успешно обновлён.');
    }

    public function test_password_change_rejects_invalid_current_password(): void
    {
        $user = $this->makeUser();

        $this->mock(AzerothCoreAccountService::class, function (MockInterface $mock) use ($user): void {
            $mock->shouldReceive('validatePassword')
                ->once()
                ->with($user, 'WrongPass123')
                ->andReturn(false);

            $mock->shouldNotReceive('updatePassword');
        });

        $response = $this->from(route('cabinet.index'))->actingAs($user)->post(route('cabinet.password.update'), [
            'current_password' => 'WrongPass123',
            'password' => 'NewPass123',
            'password_confirmation' => 'NewPass123',
        ]);

        $response->assertRedirect(route('cabinet.index'));
        $response->assertSessionHasErrors(['current_password']);
    }

    public function test_authenticated_user_can_request_client_link(): void
    {
        $user = $this->makeUser();

        $this->mock(GameClientDownloadService::class, function (MockInterface $mock): void {
            $mock->shouldReceive('temporaryUrl')
                ->once()
                ->andReturn('https://example.com/client.zip');
        });

        $response = $this->actingAs($user)->get(route('cabinet.client'));

        $response->assertRedirect('https://example.com/client.zip');
    }

    private function makeUser(int $gmLevel = 0): GameAccountUser
    {
        return new GameAccountUser(
            id: 7,
            username: 'PLAYERONE',
            email: 'PLAYER@EXAMPLE.COM',
            regMail: 'PLAYER@EXAMPLE.COM',
            gmLevel: $gmLevel,
            locked: false,
            lastLoginAt: '2026-03-13 18:00:00',
            joinedAt: '2026-03-12 12:00:00',
            saltHex: str_repeat('AA', 32),
            verifierHex: str_repeat('BB', 32),
        );
    }
}
