<?php
declare(strict_types=1);

namespace App\Controller;

use Cake\Event\EventInterface;
use Cake\Http\Response;
use Cake\I18n\DateTime;
use Cake\Routing\Router;

/**
 * Users Controller
 *
 * @property \App\Model\Table\UsersTable $Users
 */
class UsersController extends AppController
{
    /**
     * Index method
     *
     * @return \Cake\Http\Response|null|void Renders view
     */
    public function index()
    {
        $query = $this->Users->find();
        $users = $this->paginate($query);

        $this->set(compact('users'));
    }

    /**
     * View method
     *
     * @param string|null $id User id.
     * @return \Cake\Http\Response|null|void Renders view
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function view(?string $id = null)
    {
        $user = $this->Users->get($id, contain: ['Articles']);
        $this->set(compact('user'));
    }

    /**
     * Add method
     *
     * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
     */
    public function add()
    {
        $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(__('The user has been saved.'));

                return $this->redirect(['action' => 'login']);
            }
            $this->Flash->error(__('The user could not be saved. Please, try again.'));
        }
        $this->set(compact('user'));
    }

    /**
     * Edit method
     *
     * @param string|null $id User id.
     * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function edit(?string $id = null)
    {
        $user = $this->Users->get($id, contain: []);
        if ($this->request->is(['patch', 'post', 'put'])) {
            $user = $this->Users->patchEntity($user, $this->request->getData());
            if ($this->Users->save($user)) {
                $this->Flash->success(__('The user has been saved.'));

                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('The user could not be saved. Please, try again.'));
        }
        $this->set(compact('user'));
    }

    /**
     * Delete method
     *
     * @param string|null $id User id.
     * @return \Cake\Http\Response|null Redirects to index.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function delete(?string $id = null)
    {
        $this->request->allowMethod(['post', 'delete']);
        $user = $this->Users->get($id);
        if ($this->Users->delete($user)) {
            $this->Flash->success(__('The user has been deleted.'));
        } else {
            $this->Flash->error(__('The user could not be deleted. Please, try again.'));
        }

        return $this->redirect(['action' => 'index']);
    }

    /**
     * @param \Cake\Event\EventInterface $event
     * @return void
     */
    public function beforeFilter(EventInterface $event): void
    {

        parent::beforeFilter($event);
        //Configure the login action to not require authentication, preventing
        //the infinite redirect loop issue
        $this->Authentication->addUnauthenticatedActions(['login', 'logout', 'add', 'forgot', 'reset']);
    }

    /**
     * @return \App\Controller\Response|null|void
     */
    public function login()
    {
        $this->request->allowMethod(['post', 'get']);
        $result = $this->Authentication->getResult();
        //regardless of POST or GET, redirect if user is logged in
        if ($result && $result->isValid()) {
            //redirect to the admin dashboard after login succes
            $redirectToDash = $this->request->getQuery('redirect', [
                'controller' => 'Contacts',
                'action' => 'index',
            ]);

            return $this->redirect($redirectToDash);
        }

        //display error if user submitted and authentication failed
        if ($this->request->is('post') && !$result->isValid()) {
            $this->Flash->error(__('Please, enter valid username or password.'));
        }
    }

    /**
     * @return Response|void|null
     */
    public function logout()
    {
        $result = $this->Authentication->getResult();
        if ($result && $result->isValid()) {
            $this->Authentication->logout();
        }
        return $this->redirect(['controller' => 'Users', 'action' => 'login']);
    }

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

        $resetUrl = null;

        if ($this->request->is('post')) {
            $email = $this->request->getData('email');
            $user = $this->Users->find()->where(['email' => $email])->first();

            if ($user) {
                $user->reset_token = bin2hex(random_bytes(32));
                $user->token_expires = new DateTime('+10 minutes');

                if ($this->Users->save($user)) {
                    $resetUrl = Router::url(['controller' => 'Users', 'action' => 'reset', $user->reset_token], true);
                }
            } elseif (!$user) {
                $this->Flash->error(__('The email address could not be found.'));

                return $this->redirect(['controller' => 'Users', 'action' => 'forgot']);
            }
            $this->set(compact('resetUrl'));
        }
    }

    public function reset($token = null)
    {
        $this->request->allowMethod(['post', 'get']);

        if (!$token) {
            $this->Flash->error(__('Invalid reset link.'));

            return $this->redirect(['action' => 'forgot']);
        }

        $user = $this->Users->find()->where(
            [
                'reset_token' => $token,
                'token_expires >=' => DateTime::now(),
            ],
        )
            ->first();

        if (!$user) {
            $this->Flash->error(__('Invalid reset link.'));

            return $this->redirect(['action' => 'forgot']);
        }

        if ($this->request->is('post')) {
            $user = $this->Users->patchEntity($user, [
                'password' => $this->request->getData('password'),
                'reset_token' => null,
                'token_expires' => null,
            ]);

            if ($this->Users->save($user)) {
                $this->Flash->success(__('Password updated successfully. You can now login.'));

                return $this->redirect(['action' => 'login']);
            }
            $this->Flash->error(__('Password update failed.'));
        }
        $this->set(compact('token'));
    }
}
