<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\UsernameRequest;
use App\Services\UsernameApprovalService;
use App\Support\UsernamePolicy;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;

class SetupUsernameController extends Controller
{
    public function __construct(private readonly UsernameApprovalService $usernameApprovalService)
    {
    }

    public function create(Request $request): View
    {
        return view('auth.setup-username', [
            'username' => (string) ($request->user()?->username ?? ''),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $normalized = UsernamePolicy::normalize((string) $request->input('username', ''));
        $request->merge(['username' => $normalized]);

        $validated = $request->validate([
            'username' => UsernameRequest::rulesFor((int) $request->user()->id),
        ], [
            'username.required' => 'Please choose a username to continue.',
            'username.unique' => 'This username is already taken.',
            'username.regex' => 'Use only letters, numbers, and underscores.',
            'username.min' => 'Username must be at least 3 characters.',
            'username.max' => 'Username must be at most 20 characters.',
        ]);

        $candidate = (string) $validated['username'];
        $user = $request->user();

        $similar = UsernamePolicy::similarReserved($candidate);
        if ($similar !== null && ! UsernamePolicy::hasApprovedOverride($candidate, (int) $user->id)) {
            $this->usernameApprovalService->submit($user, $candidate, 'onboarding_username', [
                'current_username' => (string) ($user->username ?? ''),
            ]);

            return back()
                ->withInput()
                ->with('status', 'Your request has been submitted for manual username review.')
                ->withErrors([
                    'username' => 'This username is too similar to a reserved name and requires manual approval.',
                ]);
        }

        DB::transaction(function () use ($user, $candidate): void {
            $oldUsername = (string) ($user->username ?? '');

            if ($oldUsername !== '' && strtolower($oldUsername) !== strtolower($candidate) && Schema::hasTable('username_history')) {
                DB::table('username_history')->insert([
                    'user_id' => (int) $user->id,
                    'old_username' => strtolower($oldUsername),
                    'changed_at' => now(),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }

            if ($oldUsername !== '' && strtolower($oldUsername) !== strtolower($candidate) && Schema::hasTable('username_redirects')) {
                DB::table('username_redirects')->updateOrInsert(
                    ['old_username' => strtolower($oldUsername)],
                    [
                        'new_username' => strtolower($candidate),
                        'user_id' => (int) $user->id,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]
                );
            }

            $user->forceFill([
                'username' => strtolower($candidate),
                'onboarding_step' => 'complete',
                'username_changed_at' => now(),
                'last_username_change_at' => now(),
            ])->save();
        });

        $request->session()->forget('username_login_upgrade');

        return redirect('/@' . strtolower($candidate));
    }
}
