<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class PlayerAuthController extends Controller
{
    public function showLogin()
    {
        return view('player.login');
    }

    public function showRegister()
    {
        return view('player.register', [
            'statesCities' => config('br_states_cities'),
        ]);
    }

    public function login(Request $request): RedirectResponse
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required', 'string'],
        ]);

        if (! Auth::attempt($credentials)) {
            return back()
                ->withErrors(['email' => 'E-mail ou senha inválidos.'])
                ->onlyInput('email');
        }

        $request->session()->regenerate();

        return redirect()->intended(route('game.index'));
    }

    public function register(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'email' => ['required', 'email', 'max:190', 'unique:users,email'],
            'cpf' => ['required', 'string', 'max:18'],
            'state' => ['required', 'string', 'size:2'],
            'city' => ['required', 'string', 'max:120'],
            'password' => ['required', 'string', 'min:6', 'confirmed'],
        ]);

        $state = strtoupper(trim($data['state']));
        $statesCities = config('br_states_cities', []);

        if (! array_key_exists($state, $statesCities)) {
            return back()
                ->withErrors(['state' => 'Estado inválido.'])
                ->withInput();
        }

        $city = $this->normalizeCity($data['city']);

        if (! $this->cityExistsInState($city, $statesCities[$state])) {
            return back()
                ->withErrors(['city' => 'Selecione uma cidade válida para o estado informado.'])
                ->withInput();
        }

        $cpf = $this->normalizeCpf($data['cpf']);

        if (! $this->isValidCpf($cpf)) {
            return back()
                ->withErrors(['cpf' => 'CPF inválido.'])
                ->withInput();
        }

        if (User::query()->where('cpf', $cpf)->exists()) {
            return back()
                ->withErrors(['cpf' => 'Este CPF já está cadastrado.'])
                ->withInput();
        }

        $user = User::query()->create([
            'name' => trim($data['name']),
            'email' => strtolower(trim($data['email'])),
            'cpf' => $cpf,
            'state' => $state,
            'city' => $city,
            'password' => $data['password'],
        ]);

        Auth::login($user);
        $request->session()->regenerate();

        return redirect()->route('game.index');
    }

    public function logout(Request $request): RedirectResponse
    {
        Auth::logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect()->route('login');
    }

    private function normalizeCity(string $city): string
    {
        $clean = preg_replace('/\s+/', ' ', trim($city)) ?? trim($city);

        return mb_convert_case($clean, MB_CASE_TITLE, 'UTF-8');
    }

    private function cityExistsInState(string $city, array $cities): bool
    {
        foreach ($cities as $candidate) {
            if ($this->normalizeCity($candidate) === $city) {
                return true;
            }
        }

        return false;
    }

    private function normalizeCpf(string $cpf): string
    {
        return preg_replace('/\D+/', '', $cpf) ?? '';
    }

    private function isValidCpf(string $cpf): bool
    {
        if (strlen($cpf) !== 11) {
            return false;
        }

        if (preg_match('/^(\d)\1{10}$/', $cpf) === 1) {
            return false;
        }

        for ($t = 9; $t < 11; $t++) {
            $sum = 0;

            for ($i = 0; $i < $t; $i++) {
                $sum += ((int) $cpf[$i]) * (($t + 1) - $i);
            }

            $digit = ((10 * $sum) % 11) % 10;

            if ((int) $cpf[$t] !== $digit) {
                return false;
            }
        }

        return true;
    }
}
