<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\User;
use App\Repositories\UserRepository;
use App\Services\Session;
use App\Services\Validator;
use App\Services\View;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

/**
 * UserController
 */
class UserController extends Controller
{
    public function __construct(
        protected View $view,
        protected Session $session,
        protected Validator $validator,
        protected UserRepository $userRepository,
    ) {}

    /**
     * Login
     *
     * @param Request   $request
     * @param Response  $response
     *
     * @return Response
     */
    public function index(Request $request, Response $response): Response
    {
        $users = $this->userRepository->getUsers(setting('user.per_page'));

        return $this->view->render(
            $response,
            'users/index',
            compact('users')
        );
    }

    /**
     * Login
     *
     * @param Request   $request
     * @param Response  $response
     *
     * @return Response
     */
    public function login(Request $request, Response $response): Response
    {
        if ($request->getMethod() === 'POST') {
            $input = (array) $request->getParsedBody();

            $this->validator->required(['login', 'password']);

            if ($this->validator->isValid($input)) {
                $user = User::query()->where('login', $input['login'])->first();

                if ($user && password_verify($input['password'], $user->password)) {
                    $this->session->set('login', $user->login);
                    $this->session->set('password', $user->password);
                    $this->session->set('flash', ['success' => 'Вы успешно авторизованы!']);

                    // @TODO remember
                    $options = [
                        'expires'  => strtotime('+1 year'),
                        'path'     => '/',
                        'domain'   => setting('session.cookie_domain'),
                        'secure'   => setting('session.cookie_secure'),
                        'httponly' => setting('session.cookie_httponly'),
                        'samesite' => setting('session.cookie_samesite'),
                    ];
                    setcookie('login', $user->login, $options);
                    setcookie('password', $user->password, $options);

                    return $this->redirect($response, '/');
                }

                $this->validator->addError('login', 'Неверный логин или пароль');
            }

            $this->session->set('flash', ['errors' => $this->validator->getErrors(), 'old' => $input]);

            return $this->redirect($response, '/login');
        }

        return $this->view->render(
            $response,
            'users/login',
        );
    }

    /**
     * Register
     *
     * @param Request   $request
     * @param Response  $response
     *
     * @return Response
     */
    public function register(Request $request, Response $response): Response
    {
        if ($request->getMethod() === 'POST') {
            $input = (array) $request->getParsedBody();

            $this->validator->required(['captcha', 'login', 'password', 'password2', 'email'])
                ->same('captcha', $this->session->get('captcha'), 'Не удалось пройти проверку captcha!')
                ->length('login', 3, 20)
                ->regex('login', '|^[a-z0-9\-]+$|i')
                ->email('email')
                ->minLength(['password', 'password2'], 6)
                ->equal('password', 'password2');

            $userExists = User::query()->where('login', 'lax', $input['login'])->first();
            if ($userExists) {
                $this->validator->addError('login', 'Данный логин уже занят');
            }

            $emailExists = User::query()->where('email', 'lax', $input['email'])->first();
            if ($emailExists) {
                $this->validator->addError('email', 'Данный email уже используется');
            }

            if ($this->validator->isValid($input)) {
                $password = password_hash($input['password'], PASSWORD_BCRYPT);
                User::query()->create([
                    'login'      => sanitize($input['login']),
                    'password'   => $password,
                    'email'      => strtolower($input['email']),
                    'role'       => User::USER,
                    'created_at' => time(),
                ]);

                $this->session->set('login', $input['login']);
                $this->session->set('password', $password);
                $this->session->set('flash', ['success' => 'Вы успешно зарегистрировались!']);

                return $this->redirect($response, '/');
            }

            $this->session->set('flash', ['errors' => $this->validator->getErrors(), 'old' => $input]);

            return $this->redirect($response, '/register');
        }

        return $this->view->render(
            $response,
            'users/register',
        );
    }

    /**
     * Logout
     *
     * @param Request  $request
     * @param Response $response
     *
     * @return Response
     */
    public function logout(Request $request, Response $response): Response
    {
        $input = (array) $request->getParsedBody();

        $this->validator
            ->required('csrf')
            ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!');

        if ($this->validator->isValid($input)) {
            $this->session->delete('login');
            $this->session->delete('password');

            $options = [
                'expires' => strtotime('-1 hour'),
                'path' => '/',
                'domain'   => setting('session.cookie_domain'),
                'secure'   => setting('session.cookie_secure'),
                'httponly' => setting('session.cookie_httponly'),
                'samesite' => setting('session.cookie_samesite'),
            ];
            setcookie('password', '', $options);

            $this->session->set('flash', ['success' => 'Вы успешно вышли!']);
        } else {
            $this->session->set('flash', ['errors' => $this->validator->getErrors()]);
        }

        return $this->redirect($response, '/');
    }

    /**
     * User
     *
     * @param string   $login
     * @param Response $response
     *
     * @return Response
     */
    public function user(string $login, Response $response): Response
    {
        $user = User::query()->where('login', $login)->first();

        if (! $user) {
            abort(404, 'Пользователь не найден!');
        }

        return $this->view->render(
            $response,
            'users/user',
            compact('user')
        );
    }
}
