<?php

namespace App\Controllers\Shield;

use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Events\Events;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\Shield\Authentication\Authenticators\Session;
use CodeIgniter\Shield\Controllers\RegisterController as ShieldRegister;
use CodeIgniter\Shield\Entities\User;
use CodeIgniter\Shield\Exceptions\ValidationException;

class RegisterController extends ShieldRegister
{
    use ResponseTrait;

    protected $helpers = ['form'];

    /**
     * Displays the form the register to the site.
     *
     * @return RedirectResponse|string
     */
    public function registerView()
    {
        if (auth()->loggedIn()) {
            return redirect()->to(config('Auth')->registerRedirect());
        }

        // Check if registration is allowed
        if (! setting('Auth.allowRegistration')) {
            return redirect()->back()->withInput()
                ->with('error', lang('Auth.registerDisabled'));
        }

        /** @var Session $authenticator */
        $authenticator = auth('session')->getAuthenticator();

        // If an action has been defined, start it up.
        if ($authenticator->hasAction()) {
            return redirect()->route('auth-action-show');
        }

        return $this->view(setting('Auth.views')['register'], [
            'action'           => base_url('register'),
            'username'         => '',
            'email'            => '',
            'password'         => '',
            'password_confirm' => '',
        ]);
    }

    /**
     * Attempts to log the user in.
     */
    public function registerActionAjax()
    {
        header('Content-Type: application/json');

        if (auth()->loggedIn()) {
            return $this->respond(['message' => config('Auth')->registerRedirect()]);
        }

        // Check if registration is allowed
        if (! setting('Auth.allowRegistration')) {
            return $this->fail(lang('Auth.registerDisabled'), 400);
        }

        $users = $this->getUserProvider();

        // Validate here first, since some things,
        // like the password, can only be validated properly here.
        $rules = [
            'username'         => 'required|max_length[50]|is_unique[users.username,id,{id}]',
            'email'            => 'required|max_length[254]|valid_email|is_unique[auth_identities.secret,user_id,{id}]',
            'password'         => 'required|strong_password',
            'password_confirm' => [
                'label' => 'password confirm',
                'rules' => 'trim|required|matches[password]',
            ],
        ];

        $data = [
            'username' => trim($this->request->getPost('username')),
            'email'    => trim($this->request->getPost('email')),
            'password' => trim($this->request->getPost('password')),
        ];

        if (! $this->validate($rules)) {
            return $this->fail($this->validator->getErrors(), 400);
        }

        // Save the user
        $allowedPostFields = array_keys($rules);
        $user              = $this->getUserEntity();
        $user->fill($this->request->getPost($allowedPostFields));

        // Workaround for email only registration/login
        if ($user->username === null) {
            $user->username = null;
        }

        try {
            $users->save($user);
        } catch (ValidationException $e) {
            return $this->fail($users->errors(), 400);
        }

        // To get the complete user object with ID, we need to get from the database
        $user = $users->findById($users->getInsertID());

        // Add to default group
        $users->addToDefaultGroup($user);

        Events::trigger('register', $user);

        /** @var Session $authenticator */
        $authenticator = auth('session')->getAuthenticator();

        $authenticator->startLogin($user);

        // If an action has been defined for register, start it up.
        $hasAction = $authenticator->startUpAction('register', $user);
        if ($hasAction) {
            return $this->respond(['message' => config('Auth')->registerRedirect()]);
        }

        // Set the user active
        $user->activate();

        $authenticator->completeLogin($user);

        // Success!
        return $this->respond(['message' => config('Auth')->registerRedirect()]);
    }
}
