<?php

namespace Mtc\Modules\Members\Http\Controllers;

use App\MemberInfo;
use App\Src\Encryption;
use Carbon\Carbon;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Routing\Redirector;
use Mtc\Core\Models\Country;
use Mtc\Core\Models\CountryState;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Modules\Members\Classes\MemberManager;
use Mtc\Modules\Members\Models\Member;
use Mtc\Plugins\NewsletterSignup\Classes\Newsletter;


class AuthController extends BaseController
{
    protected Member $member;

    public function __construct()
    {
        $this->middleware(function ($request, $next) {
            if (Auth::isLoggedIn() && isset($_SESSION['member_id'])) {
                return redirect(route('members-dashboard', [], false));
            }
            return $next($request);
        });
    }

    public function login(Request $request)
    {
        $page_meta['title'] = config('app.name') . ' | Login';

        return template('members/login.twig', [
            'page_meta' => $page_meta,
            'errors' => [],
            'request' => $request->all(),
            'self' => $request->server('REQUEST_URI'),
            'is_login_page' => true,
        ]);
    }

    /**
     * Login action
     *
     * @param Request $request
     * @return Application|JsonResponse|RedirectResponse|Redirector
     */
    public function loginAction(Request $request)
    {
        $rateLimit = \Mtc\Core\RateLimit::log('login_post', 'Sorry, you have made too many requests from your IP address. Please try again in a minute.', 10);   

        if($rateLimit && $rateLimit['limited']) {
            return response()->json([
                'errors' => [
                    'message' => $rateLimit['message']
                ],
            ]);
        }

        if (empty($request->input('email'))) {
            return response()->json([
                'errors' => [
                    'email' => 'You did not enter an email address',
                ],
            ]);
        }

        if (empty($request->input('password'))) {
            return response()->json([
                'errors' => [
                    'password' => 'You did not enter a password',
                ],
            ]);
        }

        try {
            Auth::login($request->input('email'), $request->input('password'));
        } catch (\Mtc\Modules\Members\Classes\AuthenticationException $e) {
            return response()->json([
                'errors' => [
                    'email' => $e->getMessage(),
                ],
            ]);
        }
        if (!empty($request->input('redirect'))) {
            $redirect = urldecode($_REQUEST['redirect']);
        } else {
            $redirect = route('members-dashboard', [], false);
        }

        if ($request->input('ajax')) {
            return response()->json([
                'success' => [
                    'redirect' => $redirect,
                ],
            ]);
        }
        return redirect($redirect);
    }

    /**
     * Registration form
     *
     * @param Request $request
     * @return string
     */
    public function register(Request $request): string
    {
        $page_meta['title'] = config('app.name') . ' | Register';

        $breadcrumbs = [
            [
                'url' => '/',
                'name' => 'Home',
            ],
            [
                'url' => '/members/',
                'name' => 'Members',
            ],
            [
                'url' => '/',
                'name' => 'Register',
            ],
        ];

        $strings = [
            'address' => [
                'title' => 'Your address',
                'a1' => 'Address 1',
            ]
        ];

        // Render Template
        return template('members/register.twig', [
            'request' => $_REQUEST,
            'self' => $_SERVER['REQUEST_URI'],
            'page_meta' => $page_meta,
            'breadcrumbs' => $breadcrumbs,
            'countries' => Country::getFullCountryList(),
            'state_list' => CountryState::getStateList("US"),
            'genders' => Member::$genders,
            'is_dob_visible' => true,
            'is_job_title_visible' => false,
            'strings' => $strings,
            'is_login_page' => true,
            'dob' => Member::getDobOptions(),
        ]);
    }

    /**
     * Register action
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function registerAction(Request $request): JsonResponse
    {
        $rateLimit = \Mtc\Core\RateLimit::log('register_post', 'Sorry, you have made too many requests from your IP address. Please try again in a minute.', 10);   

        if($rateLimit && $rateLimit['limited']) {
            return response()->json([
                'errors' => [
                    'message' => $rateLimit['message']
                ],
            ]);
        }

        $errors = [];
        $success = [];

        $data = $request->all();
        if (!isset($data['billing_country'])) {
            $data['billing_country'] = 'GB';
        }

        $memberManager = new MemberManager();

        $savedMember = $memberManager->save($data, new Member());

        if ($savedMember) {

            $this->member = $savedMember;

            if (!empty($data['newsletter'])) {
                Newsletter::signUp($data['email'], [
                    'first_name' => $data['billing_firstname'],
                    'last_name' => $data['billing_lastname'],
                    'skip_double_opt_in' => true,
                ]);
            }

            MemberInfo::registerSiteOfOrigin($this->member, SITE_ID);

            // log the member in after successful registration
            Auth::login($this->member);

            if (!empty($_REQUEST['redirect'])) {
                $redirect = urldecode($_REQUEST['redirect']);
                $success['redirect'] = $redirect;
            } else {
                $success['redirect'] = route('members-verify', [], false);
            }

        } else {
            $errors = $memberManager->getErrors();
        }

        return response()->json([
            'errors' => $errors,
            'success' => $success,
        ]);
    }

    /**
     * Forgotten password form
     *
     * @param Request $request
     * @return string
     */
    public function passwordReminder(Request $request): string
    {
        $page_meta['title'] = config('app.name') . ' | Password Reminder';

        return template('members/forgot/trigger_password_reminder.twig', [
            'page_data' => [],
            'page_meta' => $page_meta,
        ]);
    }

    /**
     * Password reminder action
     *
     * @param Request $request
     * @return JsonResponse
     * @throws Exception
     */
    public function passwordReminderAction(Request $request): JsonResponse
    {
        if (!filter_var($request->input('email'), FILTER_VALIDATE_EMAIL)) {
            return response()->json([
                'errors' => [
                    'email' => "You did not provide a valid email address",
                ],
                'success' => [],
            ]);
        }

        $email = $request->input('email');

        $member = Member::query()
            ->where('email_hash', Encryption::makeHash($email))
            ->first(['id', 'email']);

        // Only reset password if the user is already registered, but make it look like
        // it's been reset to satisfy spammers trying to get email addresses.
        if (empty($member)) {
            return response()->json([
                'errors' => [
                    'email' => "We can't find any user with that email address"
                ],
                'success' => [],
            ]);
        }
        $hash = Auth::initiatePasswordReset($member);

        $params = [
            'reset_email' => $member->email,
            'reset_code'  => $hash,
        ];

        $content = template('emails/members/reset_password.twig', [
            'member' => $member,
            'url' => route('members-reset-password', $params),
        ]);

        email($member->email, config('app.name') . ' Password Reset', $content);

        return response()->json([
            'errors' => [],
            'success' => [
                'message' => '<p>We have sent an email with a link to reset your password... following this link will allow you to set a new password.</p><p class="success">Please check your email for further instructions</p>',
                'hide_form' => true
            ],
        ]);
    }

    /**
     * Forgotten password form
     *
     * @param Request $request
     * @return string
     */
    public function resetPassword(Request $request): string
    {
        $page_meta['title'] = config('app.name') . ' | Reset Password';

        return template('members/forgot/reset_password.twig', [
            'request' => $request->all(),
            'page_meta' => $page_meta,
        ]);
    }

    /**
     * Password reminder action
     *
     * @param Request $request
     * @return JsonResponse
     * @throws Exception
     */
    public function resetPasswordAction(Request $request): JsonResponse
    {
        $member = Auth::matchMemberByHash(
            $request->input('reset_email'),
            $request->input('reset_code')
        );

        if (empty($member)) {
            return response()->json([
                'errors' => [
                    'unique_code' => "The unique code did not match. This may have expired. Please request a new password reset",
                ],
                'success' => [],
            ]);
        }

        if (mb_strlen($request->input('password')) < 8) {
            return response()->json([
                'errors' => [
                    'password' => "Your password must be at least 8 characters",
                ],
                'success' => [],
            ]);
        }

        if ($request->input('password') != $request->input('password2')) {
            return response()->json([
                'errors' => [
                    'password2' => "The passwords you entered do not match",
                ],
                'success' => [],
            ]);
        }

        $member->setPassword($request->input('password'));
        if (empty($member->first_login)) {
            $member->first_login = new Carbon();
        }
        $member->save();

        Auth::login($member->email, $request->input('password'));

        // Honour an optional redirect param the same way loginAction does, so
        // a member who started from a deep link continues there instead of
        // landing on the generic dashboard. Only accept internal relative
        // paths to prevent open redirects.
        $redirect = route('members-dashboard', [], false);
        $redirectInput = urldecode((string) $request->input('redirect', ''));
        if (str_starts_with($redirectInput, '/') && !str_starts_with($redirectInput, '//')) {
            $redirect = $redirectInput;
        }

        return response()->json([
            'errors' => [],
            'success' => [
                'message' => '<p class="success">We have succesfully updated your password.</p><p><a href="' . htmlspecialchars($redirect, ENT_QUOTES) . '">Please click here to continue to the Member\'s Area.</a></p>',
                'hide_form' => true,
                'redirect' => $redirect,
            ],
        ]);
    }

    /**
     * User login / temp account creation
     *
     * @param Request $request
     * @return string
     */
    public function registerExpress(Request $request): string
    {
        $title = !empty('book') ?
            'Book an online appointment' :
            'Account';
        $page_meta['title'] = config('app.name') . ' | ' . $title;

        return template('members/registerExpress.twig', [
            'page_meta' => $page_meta,
            'title' => $title,
            'errors' => [],
            'request' => $request->all(),
            'self' => $request->server('REQUEST_URI'),
            'is_login_page' => true,
        ]);
    }

    /**
     * Express register action
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function registerExpressAction(Request $request): JsonResponse
    {
        $memberManager = new MemberManager();

        if (!$member = $memberManager->saveExpress($request->all())) {
            return response()->json([
                'errors' => $memberManager->getErrors(),
                'success' => [],
            ]);
        }

        // log the member in after successful registration
        Auth::login($member);

        return response()->json([
            'errors' => [],
            'success' => [
                'redirect' => !empty($request->input('redirect')) ?
                    urldecode($request->input('redirect')) :
                    '/members/',
            ],
        ]);
    }
}
