<?php
declare(strict_types=1);

namespace App\Controller;

use App\Model\Table\UsersTable;
use Cake\I18n\DateTime;
use Cake\Mailer\Mailer;
use Cake\Utility\Security;

class AuthController extends AppController
{
    private UsersTable $Users;

    public function initialize(): void
    {
        parent::initialize();
        $this->Authentication->allowUnauthenticated(['login', 'forgetPassword', 'resetPassword','register']);
        $this->Users = $this->fetchTable('Users');
    }

    public function register()
    {
        $user = $this->Users->newEmptyEntity();
        if ($this->request->is('post')) {
            $user = $this->Users->patchEntity($user, $this->request->getData());
            if ($this->Users->save($user)) {
                $this->Flash->success('You have been registered. Please log in. ');
                return $this->redirect(['action' => 'login']);
            }
            $this->Flash->error('The user could not be registered. Please, try again.');
        }
        $this->set(compact('user'));
    }

    public function forgetPassword()
    {
        if ($this->request->is('post')) {
            $user = $this->Users->findByEmail($this->request->getData('email'))->first();
            if ($user) {
                $user->nonce = Security::randomString(128);
                $user->nonce_expiry = new DateTime('7 days');
                if ($this->Users->save($user)) {
                    $mailer = new Mailer('default');
                    $mailer->setEmailFormat('both')->setTo($user->email)->setSubject('Reset your account password');
                    $mailer->viewBuilder()->setTemplate('reset_password');
                    $mailer->setViewVars([
                        'first_name' => $user->first_name,
                        'last_name' => $user->last_name,
                        'nonce' => $user->nonce,
                        'email' => $user->email,
                    ]);
                    if (!$mailer->deliver()) {
                        $this->Flash->error('We have encountered an issue when sending you emails. Please try again. ');
                        return $this->render();
                    }
                } else {
                    $this->Flash->error('We are having issue to reset your password. Please try again. ');
                    return $this->render();
                }
            }
            $this->Flash->success('Please check your inbox (or spam folder) for an email regarding how to reset your account password. ');
            return $this->redirect(['action' => 'login']);
        }
    }

    public function resetPassword(?string $nonce = null)
    {
        $user = $this->Users->findByNonce($nonce)->first();
        if (!$user || $user->nonce_expiry < DateTime::now()) {
            $this->Flash->error('Your link is invalid or expired. Please try again.');
            return $this->redirect(['action' => 'forgetPassword']);
        }
        if ($this->request->is(['patch', 'post', 'put'])) {
            $user = $this->Users->patchEntity($user, $this->request->getData(), ['validate' => 'resetPassword']);
            $user->nonce = null;
            $user->nonce_expiry = null;
            if ($this->Users->save($user)) {
                $this->Flash->success('Your password has been successfully reset. Please login with new password. ');
                return $this->redirect(['action' => 'login']);
            }
            $this->Flash->error('The password cannot be reset. Please try again.');
        }
        $this->set(compact('user'));
    }

    public function changePassword(?string $id = null)
    {
        $user = $this->Users->get($id, ['contain' => []]);
        if ($this->request->is(['patch', 'post', 'put'])) {
            $user = $this->Users->patchEntity($user, $this->request->getData(), ['validate' => 'resetPassword']);
            if ($this->Users->save($user)) {
                $this->Flash->success('The user has been saved.');
                return $this->redirect(['controller' => 'Users', 'action' => 'index']);
            }
            $this->Flash->error('The user could not be saved. Please, try again.');
        }
        $this->set(compact('user'));
    }

    public function login()
    {
        $this->request->allowMethod(['get', 'post']);

        if ($this->request->is('post')) {
            $captchaResponse = (string)($this->request->getData('g-recaptcha-response') ?? '');
            if ($captchaResponse === '') {
                $result = $this->Authentication->getResult();
                if ($result && $result->isValid()) {
                    $this->Authentication->logout();
                }
                $this->Flash->error('Please complete the reCAPTCHA verification');
                return $this->redirect(['controller' => 'Auth', 'action' => 'login']);
            }

            $secret = env('RECAPTCHA_SECRET_V2', '6Lf00OIrAAAAAB0lqpx8ESI0umIOaD3T8Wg-lccJ');
            $verifyUrl = 'https://www.google.com/recaptcha/api/siteverify';
            $options = [
                'http' => [
                    'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
                    'method'  => 'POST',
                    'content' => http_build_query([
                        'secret'   => $secret,
                        'response' => $captchaResponse,
                        //'remoteip' => $this->request->clientIp(),
                    ]),
                    'timeout' => 8,
                ],
            ];
            $context = stream_context_create($options);
            $resultJson = @file_get_contents($verifyUrl, false, $context);
            $data = $resultJson ? json_decode($resultJson, true) : null;

            if (empty($data['success'])) {
                $this->Flash->error('reCAPTCHA verification failed. Please try again.');
                return $this->redirect(['controller' => 'Auth', 'action' => 'login']);
            }

            $result = $this->Authentication->getResult();
            if ($result && $result->isValid()) {
                $fallbackLocation = ['controller' => 'Admin', 'action' => 'index'];
                return $this->redirect($this->Authentication->getLoginRedirect() ?? $fallbackLocation);
            }

            if ($this->request->is('post') && (!$result || !$result->isValid())) {
                $this->Flash->error('Email address and/or Password is incorrect. Please try again. ');
            }
        }
    }

    public function logout()
    {
        $result = $this->Authentication->getResult();
        if ($result && $result->isValid()) {
            $this->Authentication->logout();
            $this->Flash->success('You have been logged out successfully. ');
        }
        return $this->redirect(['controller' => 'Auth', 'action' => 'login']);
    }
}
