<?php

namespace App\Http\Controllers;

use App\Exceptions\DuplicateGameAccountException;
use App\Exceptions\InviteCodeException;
use App\Http\Requests\RegisterGameAccountRequest;
use App\Models\News;
use App\Services\AzerothCoreAccountRegistrar;
use App\Services\AzerothCoreAccountService;
use App\Services\InviteCodeService;
use App\Services\NewsService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Throwable;

class LandingController extends Controller
{
    public function index(
        Request $request,
        AzerothCoreAccountService $accounts,
        NewsService $news,
    ): View
    {
        $realmConfig = config('moonwell.realm');
        $rates = $realmConfig['rates'] ?? [];
        $user = Auth::user();
        $playersOnline = $accounts->onlinePlayerCount();

        $playUrl = $user !== null
            ? route('cabinet.client')
            : '#join';

        $posts = $news->listForLanding()
            ->values()
            ->map(fn (News $item, int $index): array => [
                'id' => $item->id,
                'title' => $item->title,
                'excerpt' => Str::limit(trim(strip_tags($item->body)), 200),
                'date' => $item->created_at?->locale(app()->getLocale())->isoFormat('D MMMM YYYY'),
                'tag' => 'Новости',
                'tagType' => 'patch',
                'image_url' => $item->image_url,
                'featured' => $index === 0,
            ])
            ->all();

        $bootstrap = [
            'realm' => [
                'name' => $realmConfig['realm_name'],
                'mode' => sprintf('PvE · %s rate · RU', $rates['experience'] ?? 'x1'),
                'realmlist' => $realmConfig['realmlist'],
                'online' => $playersOnline !== null,
                'players' => $playersOnline,
                'uptime' => '99.94%',
                'ping' => 38,
                'factions' => ['alliance' => 52, 'horde' => 48],
                'rates' => $rates,
                'client_version' => $realmConfig['client_version'] ?? '3.3.5a',
                'tagline' => $realmConfig['tagline'] ?? null,
            ],
            'play_url' => $playUrl,
            'posts' => $posts,
            'tweaks' => [
                'variant' => 'forest',
                'particles' => true,
                'moon' => true,
            ],
            'register_endpoint' => route('game-account.store'),
            'csrf_token' => csrf_token(),
            'auth' => [
                'authenticated' => $user !== null,
                'is_admin' => $user?->canAccessAdminPanel() ?? false,
                'username' => $user?->username,
                'login_url' => route('login'),
                'cabinet_url' => route('cabinet.index'),
                'admin_url' => route('admin.accounts.index'),
            ],
            'flash' => [
                'success' => $request->session()->get('registration_success'),
                'success_username' => $request->session()->get('registration_username'),
                'error' => $request->session()->get('registration_error'),
                'errors' => $this->errorBag(),
                'old' => $request->session()->getOldInput() ? [
                    'username' => $request->session()->getOldInput('username'),
                    'email' => $request->session()->getOldInput('email'),
                    'invite_code' => $request->session()->getOldInput('invite_code'),
                ] : [],
            ],
        ];

        return view('landing', [
            'bootstrap' => $bootstrap,
            'realm' => $realmConfig,
        ]);
    }

    public function register(
        RegisterGameAccountRequest $request,
        AzerothCoreAccountRegistrar $registrar,
        InviteCodeService $inviteCodes,
    ): RedirectResponse
    {
        try {
            $result = $inviteCodes->redeemForRegistration(
                $request->string('invite_code')->toString(),
                $request->string('username')->toString(),
                fn (): array => $registrar->register(
                    $request->string('username')->toString(),
                    $request->string('email')->toString(),
                    $request->string('password')->toString(),
                ),
            );
        } catch (DuplicateGameAccountException $exception) {
            return back()
                ->withErrors([$exception->field => $exception->getMessage()])
                ->withInput($request->safe()->only(['username', 'email', 'invite_code']));
        } catch (InviteCodeException $exception) {
            return back()
                ->withErrors([$exception->field => $exception->getMessage()])
                ->withInput($request->safe()->only(['username', 'email', 'invite_code']));
        } catch (Throwable $exception) {
            report($exception);

            return back()
                ->with('registration_error', 'Не удалось создать аккаунт. Проверь настройки сервера и попробуй снова.')
                ->withInput($request->safe()->only(['username', 'email', 'invite_code']));
        }

        return redirect()
            ->route('landing.index')
            ->with('registration_success', sprintf('Игровой аккаунт %s успешно создан. Теперь можно входить в клиент WoW.', $result['username']))
            ->with('registration_username', $result['username']);
    }

    /**
     * @return array<string, array<int, string>>
     */
    private function errorBag(): array
    {
        $errors = session()->get('errors');
        if (!$errors) {
            return [];
        }

        $bag = method_exists($errors, 'getBag') ? $errors->getBag('default') : $errors;

        return method_exists($bag, 'toArray') ? $bag->toArray() : [];
    }
}
