<?php

namespace Tests\Feature;

use App\Models\GameAccountUser;
use App\Models\LoginScreenNews;
use App\Services\LoginScreenNewsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LoginScreenNewsFeatureTest extends TestCase
{
    use RefreshDatabase;

    public function test_public_feed_returns_published_news_in_sort_order(): void
    {
        LoginScreenNews::query()->create([
            'title' => 'Draft',
            'body' => 'HIDDEN',
            'sort_order' => 1,
            'is_published' => false,
        ]);

        LoginScreenNews::query()->create([
            'title' => 'Late',
            'body' => "SERVERALERT:\n\n|cFF111111Late|r",
            'sort_order' => 20,
            'is_published' => true,
        ]);

        LoginScreenNews::query()->create([
            'title' => 'Early',
            'body' => '|cFF222222Early|r',
            'sort_order' => 10,
            'is_published' => true,
        ]);

        $response = $this->get(route('launcher.login-news.show'));

        $response->assertOk();
        $response->assertHeader('Content-Type', 'text/plain; charset=UTF-8');
        $response->assertContent(
            LoginScreenNewsService::FEED_HEADER
            ."\n\n|cFF222222Early|r\n"
            .LoginScreenNewsService::SECTION_SEPARATOR
            ."\n|cFF111111Late|r\n"
        );
    }

    public function test_public_feed_returns_fallback_message_when_no_news_is_published(): void
    {
        LoginScreenNews::query()->create([
            'title' => 'Draft',
            'body' => 'HIDDEN',
            'sort_order' => 0,
            'is_published' => false,
        ]);

        $response = $this->get(route('launcher.login-news.show'));

        $response->assertOk();
        $response->assertContent(
            LoginScreenNewsService::FEED_HEADER
            ."\n\n"
            .LoginScreenNewsService::EMPTY_MESSAGE
            ."\n"
        );
    }

    public function test_regular_player_cannot_open_admin_news_page(): void
    {
        $response = $this->actingAs($this->makeUser(0))->get(route('admin.login-screen-news.index'));

        $response->assertForbidden();
    }

    public function test_admin_can_open_admin_news_page(): void
    {
        LoginScreenNews::query()->create([
            'title' => 'Wrath Update',
            'body' => '|cFF00D1FFWrath update|r',
            'sort_order' => 0,
            'is_published' => true,
        ]);

        $response = $this->actingAs($this->makeUser(3))->get(route('admin.login-screen-news.index'));

        $response->assertOk();
        $response->assertSee('Новости логин-экрана WoW');
        $response->assertSee('Wrath Update');
        $response->assertSee(route('launcher.login-news.show'), false);
    }

    public function test_admin_page_always_renders_feed_link_with_http_scheme(): void
    {
        $response = $this->withServerVariables([
            'HTTP_X_FORWARDED_PROTO' => 'https',
            'HTTP_X_FORWARDED_HOST' => 'moon-well.online',
            'HTTP_X_FORWARDED_PORT' => 443,
            'HTTP_HOST' => 'moon-well.online',
            'REMOTE_ADDR' => '127.0.0.1',
        ])->actingAs($this->makeUser(3))->get(route('admin.login-screen-news.index'));

        $response->assertOk();
        $response->assertSee('http://moon-well.online/launcher/login-news.txt', false);
    }

    public function test_admin_can_create_update_and_delete_news_item(): void
    {
        $admin = $this->makeUser(3);

        $createResponse = $this->from(route('admin.login-screen-news.index'))
            ->actingAs($admin)
            ->post(route('admin.login-screen-news.store'), [
                'title' => 'Launch Notice',
                'body' => '|cFFFFD700Server launch tonight|r',
                'sort_order' => 5,
                'is_published' => '1',
            ]);

        $createResponse->assertRedirect(route('admin.login-screen-news.index'));
        $createResponse->assertSessionHas('status', 'Новость для логин-экрана добавлена.');
        $this->assertDatabaseHas('login_screen_news', [
            'title' => 'Launch Notice',
            'sort_order' => 5,
            'is_published' => 1,
            'created_by_username' => 'ADMIN',
            'updated_by_username' => 'ADMIN',
        ]);

        $newsItem = LoginScreenNews::query()->firstOrFail();

        $updateResponse = $this->from(route('admin.login-screen-news.index'))
            ->actingAs($admin)
            ->patch(route('admin.login-screen-news.update', $newsItem), [
                'title' => 'Launch Notice Updated',
                'body' => '|cFFFFD700Server launch moved to Friday|r',
                'sort_order' => 8,
            ]);

        $updateResponse->assertRedirect(route('admin.login-screen-news.index'));
        $updateResponse->assertSessionHas('status', 'Новость для логин-экрана обновлена.');
        $this->assertDatabaseHas('login_screen_news', [
            'id' => $newsItem->id,
            'title' => 'Launch Notice Updated',
            'sort_order' => 8,
            'is_published' => 0,
        ]);

        $deleteResponse = $this->from(route('admin.login-screen-news.index'))
            ->actingAs($admin)
            ->delete(route('admin.login-screen-news.destroy', $newsItem));

        $deleteResponse->assertRedirect(route('admin.login-screen-news.index'));
        $deleteResponse->assertSessionHas('status', 'Новость для логин-экрана удалена.');
        $this->assertDatabaseMissing('login_screen_news', [
            'id' => $newsItem->id,
        ]);
    }

    private function makeUser(int $gmLevel): GameAccountUser
    {
        return new GameAccountUser(
            id: 1,
            username: 'ADMIN',
            email: 'ADMIN@EXAMPLE.COM',
            regMail: 'ADMIN@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),
        );
    }
}
