<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\AdminUser;
use Core\Controller;
use Core\Csrf;
use Core\Session;

final class AdminUserController extends Controller
{
    public function index(): void
    {
        $this->requireAdminRole();

        $this->view('admin/users/index', [
            'users' => AdminUser::all(),
            'success' => Session::getFlash('success'),
            'error' => Session::getFlash('error'),
            'adminUser' => AdminUser::current(),
            'roleOptions' => AdminUser::roleOptions(),
        ], 'admin');
    }

    public function create(): void
    {
        $this->requireAdminRole();

        $this->view('admin/users/create', [
            'errors' => Session::errors(),
            'error' => Session::getFlash('error'),
            'adminUser' => AdminUser::current(),
            'roleOptions' => AdminUser::roleOptions(),
        ], 'admin');
    }

    public function store(): void
    {
        $this->requireAdminRole();

        if (!Csrf::verify($_POST['_token'] ?? null)) {
            Session::flash('error', 'Sua sessão expirou. Atualize a página e tente novamente.');
            $this->redirectTo('admin/usuarios/novo');
        }

        $name = trim((string) ($_POST['name'] ?? ''));
        $email = strtolower(trim((string) ($_POST['email'] ?? '')));
        $password = (string) ($_POST['password'] ?? '');
        $passwordConfirmation = (string) ($_POST['password_confirmation'] ?? '');
        $role = AdminUser::normalizeRole((string) ($_POST['role'] ?? 'operador'));
        $isActive = (int) ($_POST['is_active'] ?? 1);

        $errors = $this->validateUserPayload($name, $email, $password, $passwordConfirmation, $role, null, true);

        if (!empty($errors)) {
            Session::flash('error', 'Revise os dados do usuário do painel.');
            Session::putErrors($errors);
            Session::putOldInput($_POST);
            $this->redirectTo('admin/usuarios/novo');
        }

        AdminUser::create([
            'name' => $name,
            'email' => $email,
            'password_hash' => password_hash($password, PASSWORD_DEFAULT),
            'role' => $role,
            'is_active' => $isActive,
        ]);

        Session::flash('success', 'Usuário do painel criado com sucesso.');
        $this->redirectTo('admin/usuarios');
    }

    public function edit(string $id): void
    {
        $this->requireAdminRole();

        $user = AdminUser::find((int) $id);

        if (!$user) {
            http_response_code(404);
            exit('Usuário do painel não encontrado.');
        }

        $this->view('admin/users/edit', [
            'user' => $user,
            'errors' => Session::errors(),
            'error' => Session::getFlash('error'),
            'adminUser' => AdminUser::current(),
            'roleOptions' => AdminUser::roleOptions(),
        ], 'admin');
    }

    public function update(string $id): void
    {
        $this->requireAdminRole();

        $userId = (int) $id;

        if (!Csrf::verify($_POST['_token'] ?? null)) {
            Session::flash('error', 'Sua sessão expirou. Atualize a página e tente novamente.');
            $this->redirectTo('admin/usuarios/' . $userId . '/editar');
        }

        $user = AdminUser::find($userId);

        if (!$user) {
            http_response_code(404);
            exit('Usuário do painel não encontrado.');
        }

        $currentUser = AdminUser::current();
        $name = trim((string) ($_POST['name'] ?? ''));
        $email = strtolower(trim((string) ($_POST['email'] ?? '')));
        $password = (string) ($_POST['password'] ?? '');
        $passwordConfirmation = (string) ($_POST['password_confirmation'] ?? '');
        $role = AdminUser::normalizeRole((string) ($_POST['role'] ?? 'operador'));
        $isActive = (int) ($_POST['is_active'] ?? 0);

        $errors = $this->validateUserPayload($name, $email, $password, $passwordConfirmation, $role, $userId, false);

        if ($isActive !== 1 && $currentUser && (int) $currentUser['id'] === $userId) {
            $errors['is_active'] = 'Você não pode desativar o próprio usuário logado.';
        }

        $wasActiveAdmin = (int) $user['is_active'] === 1 && AdminUser::isAdmin($user);
        $willBeActiveAdmin = $isActive === 1 && $role === 'admin';

        if ($wasActiveAdmin && !$willBeActiveAdmin && AdminUser::countActiveAdmins() <= 1) {
            $errors['role'] = 'É necessário manter pelo menos um administrador ativo com perfil administrador.';
        }

        if (!empty($errors)) {
            Session::flash('error', 'Revise os dados do usuário do painel.');
            Session::putErrors($errors);
            Session::putOldInput($_POST);
            $this->redirectTo('admin/usuarios/' . $userId . '/editar');
        }

        $payload = [
            'name' => $name,
            'email' => $email,
            'role' => $role,
            'is_active' => $isActive,
        ];

        if ($password !== '') {
            $payload['password_hash'] = password_hash($password, PASSWORD_DEFAULT);
        }

        AdminUser::updateProfile($userId, $payload);

        Session::flash('success', 'Usuário do painel atualizado com sucesso.');
        $this->redirectTo('admin/usuarios');
    }

    public function toggleStatus(string $id): void
    {
        $this->requireAdminRole();

        if (!Csrf::verify($_POST['_token'] ?? null)) {
            Session::flash('error', 'Sua sessão expirou. Atualize a página e tente novamente.');
            $this->redirectTo('admin/usuarios');
        }

        $userId = (int) $id;
        $user = AdminUser::find($userId);
        $currentUser = AdminUser::current();

        if (!$user) {
            http_response_code(404);
            exit('Usuário do painel não encontrado.');
        }

        $newStatus = !(bool) $user['is_active'];

        if (!$newStatus && $currentUser && (int) $currentUser['id'] === $userId) {
            Session::flash('error', 'Você não pode desativar o próprio usuário logado.');
            $this->redirectTo('admin/usuarios');
        }

        if (
            !$newStatus &&
            (int) $user['is_active'] === 1 &&
            AdminUser::isAdmin($user) &&
            AdminUser::countActiveAdmins() <= 1
        ) {
            Session::flash('error', 'É necessário manter pelo menos um administrador ativo com perfil administrador.');
            $this->redirectTo('admin/usuarios');
        }

        AdminUser::updateStatus($userId, $newStatus);

        Session::flash('success', $newStatus
            ? 'Usuário do painel ativado com sucesso.'
            : 'Usuário do painel desativado com sucesso.');

        $this->redirectTo('admin/usuarios');
    }

    private function validateUserPayload(
        string $name,
        string $email,
        string $password,
        string $passwordConfirmation,
        string $role,
        ?int $ignoreId,
        bool $passwordRequired
    ): array {
        $errors = [];

        if ($name === '') {
            $errors['name'] = 'Informe o nome do usuário.';
        } elseif (strlen($name) < 3) {
            $errors['name'] = 'O nome deve ter ao menos 3 caracteres.';
        }

        if ($email === '') {
            $errors['email'] = 'Informe o e-mail do usuário.';
        } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $errors['email'] = 'Informe um e-mail válido.';
        } elseif (AdminUser::emailExists($email, $ignoreId)) {
            $errors['email'] = 'Já existe outro usuário com este e-mail.';
        }

        if (!array_key_exists($role, AdminUser::roleOptions())) {
            $errors['role'] = 'Selecione um tipo de usuário válido.';
        }

        if ($passwordRequired && $password === '') {
            $errors['password'] = 'Informe uma senha para o usuário.';
        }

        if ($password !== '') {
            if (strlen($password) < 8) {
                $errors['password'] = 'A senha deve ter no mínimo 8 caracteres.';
            }

            if ($password !== $passwordConfirmation) {
                $errors['password_confirmation'] = 'A confirmação da senha não confere.';
            }
        }

        return $errors;
    }
}
