<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Mail\AdminAuth;
use App\Mail\RecoveryPassword;
use App\Mail\Registration;
use App\Models\Bills\TAccountCashMst;
use App\Models\Game\CF_MEMBER;
use App\Models\Web\CF_WEB_ADMIN_OTP;
use App\Models\Web\CF_WEB_FORUM_REGISTER;
use App\Models\Web\CF_WEB_GO_USER_INFO;
use App\Models\Web\CF_WEB_QUESTION_INFO;
use App\Models\Web\Forum\mybb_users;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    public function login ()
    {
        return view("auth.login");
    }

    public function loginMissingData (Request $request)
    {
        if ($this->isAuthenticated())
        {
            try {
                $member = CF_MEMBER::where("USN", $this->getUserUSN())->firstOrFail(["USN", "NAME", "SURNAME", "PHONE", "SEC_QUESTION", "SEC_ANSWER"]);
            } catch (ModelNotFoundException $e) {
                \Session::flush();
                return redirect()->route("auth.login")->withError(__("responses.Common.UserNotFound"));
            }

            // this data is when question ID is wrong for example so questions will be returned into this data variable.
            $data = array();

            // for question we need to check if question ID exists too.
            $questionMissing = null;
            if (is_null($questions = CF_WEB_QUESTION_INFO::where("QST_ID", $member->SEC_QUESTION)->first()) || is_null($member->SEC_QUESTION)) {
                $questionMissing = true;
                $data = [
                    "questions" => CF_WEB_QUESTION_INFO::get()
                ];
            }

            $answerMissing = null;
            if (is_null($member->SEC_ANSWER)) {
                $answerMissing = true;
                if (!$questionMissing) {
                    $data = array_merge($data, [
                        "question" => CF_WEB_QUESTION_INFO::where("QST_ID", $member->SEC_QUESTION)->first(["QST_TEXT"])->QST_TEXT
                    ]);
                }
            }

            $missingData = [
                "name" => is_null($member->NAME) ?? false,
                "lastName" => is_null($member->SURNAME) ?? false,
                "phone" => is_null($member->PHONE) ?? false,
                "question" => $questionMissing,
                "answer" => $answerMissing
            ];

            if (!in_array(true, $missingData, true)) {
                return redirect()->home();
            }

            return view("auth.login-complete-data", compact("missingData", "data"));
        }

        return redirect()->route("auth.login");
    }

    public function forgotPassword ()
    {
        return view("auth.forgot-password");
    }

    public function forgotPasswordConfirm (Request $request, $token)
    {
        try {
            $user = CF_MEMBER::where("PASS_RECOVER_TOKEN", $token)->firstOrFail(["USN", "SEC_QUESTION", "SEC_ANSWER"]);
        } catch (ModelNotFoundException $e) {
            return redirect()->route("auth.login")->withError(__("responses.Common.UserNotFound"));
        }

        $questionIsNull = false;
        if (is_null($user->SEC_QUESTION)) {
            $questionIsNull = true;
        }

        $answerIsNull = false;
        if (is_null($user->SEC_ANSWER)) {
            $answerIsNull = true;
        }

        return view("auth.forgot-password-confirm")->withQuestions(CF_WEB_QUESTION_INFO::get())->with([
            "token" => $token,
            "questionIsNull" => $questionIsNull,
            "answerIsNull" => $answerIsNull
        ]);
    }

    public function adminAuth (Request $request, $token)
    {
        try {
            $auth = CF_WEB_ADMIN_OTP::where("TOKEN", $token)->where("USED_YN", 'N')->firstOrFail();

            if ($request->getClientIp() !== $auth->USER_IP) {
                \Log::error("REQUEST_IP=" . $request->getClientIp() . " AUTH_IP=" . $auth->USER_IP);
                return abort(404);
            }

            try {
                $user = CF_MEMBER::where("USN", $auth->USN)->firstOrFail(["USN", "USER_ID", "E_MAIL", "AUTHORITY_LEV", "EMAIL_VERIFY_YN"]);
            } catch (ModelNotFoundException $e) {
                \Log::error("EXCEPTION=" . $e->getMessage());
                return abort(404);
            }

            // check authority again
            if ($user->AUTHORITY_LEV < 1) {
                \Log::error("AUTHORITY_LEV=" . $user->AUTHORITY_LEV);
                return abort(404);
            }

            // yes, the member obtained from $auth is equal to $user, but security never hurts :)
            if ($user->USN != $auth->USN) {
                \Log::error("USER_USN=" . $user->USN . " AUTH_USN=" . $auth->USN);
                return abort(404);
            }

            $auth_upd = $auth->update([
                "USED_YN" => 'Y'
            ]);
            if ($auth_upd)
            {
                // adm token
                \Helper::web_createUserSession($request, $user->toArray(), [
                    "A_TOKEN" => encrypt($token)
                ]);

                return view('auth.admin-check')->with([
                    "result" => true,
                    "title" => __("responses.LoginController.Authenticated"),
                    "msg" => __("responses.LoginController.AuthneticatedMsg")
                ]);
            } else {
                $auth->update(["WRONG_ATTEMPT_IP" => $request->getClientIp()]);
                return view("auth.admin-check")->with([
                    "result" => false,
                    "title" => __("responses.LoginController.AuthenticationFailed"),
                    "msg" => __("responses.LoginController.AuthenticationFailedMsg")
                ]);
            }
        } catch (ModelNotFoundException $e) {
            \Log::error("EXCEPTION=" . $e->getMessage());
            return abort(404);
        }
    }

    ///
    /// do
    ///

    public function doLogin (Request $request, $returnUrl = false)
    {
        \Validator::make($request->post(), [
            "username" => "bail|required|max:13",
            "password" => "required"
        ])->validate();

        $username = $request->input('username');
        $password = $request->input('password');

        try {
            $user = CF_MEMBER::where("USER_ID", $username)
                ->firstOrFail(["USN", "USER_ID", "REG_DATE", "E_MAIL", "AUTHORITY_LEV", "EMAIL_VERIFY_YN", "EMAIL_VERIFY_TOKEN", "WEB_PASSWORD"]);
        } catch (ModelNotFoundException $e) {
            return redirect()->route("auth.login")->withError(__("responses.Common.UserNotFound"));
        }

        if (!\Hash::check($password, $user->WEB_PASSWORD)) {
            return redirect()->route("auth.login")->withError(__("responses.Common.PasswordInvalid"));
        }

        if ($user->EMAIL_VERIFY_YN == 'N')
        {
            if (now()->getTimestamp() > Carbon::parse($user->REG_DATE)->addHours(48)->getTimestamp()) {
                \Mail::to($user->E_MAIL)->send(new Registration($user->USER_ID, $user->EMAIL_VERIFY_TOKEN));
                return redirect()->back()->withSuccess(__("responses.LoginController.ExpiredConfirmation"));
            }

            return redirect()->back()->withError(__("responses.LoginController.ConfirmationAlert"));
        }

        if (is_null(mybb_users::where("USER_ID", $user->USER_ID)->first())) {
            if (!$this->doCreateForumAccount($user)) {
                return redirect()->back()->withError(__("responses.LoginController.ForumCreateFailed"));
            }
        }

        /*if ($user->AUTHORITY_LEV >= 1)
        {
            $token = md5($user->USER_ID . time());
            $auth = new CF_WEB_ADMIN_OTP;
            $auth->USN = $user->USN;
            $auth->TOKEN = $token;
            $auth->USER_IP = $request->getClientIp();
            if ($auth->save()) {
                \Mail::to($user->E_MAIL)->send(new AdminAuth(
                    $user->USER_ID,
                    $token
                ));
                return redirect()->back()->withError("Quase lá, verifique seu e-mail para mais informações.");
            } else {
                return redirect()->back()->withError("Oops, não foi possível autenticar seu usuário, tente novamente!");
            }
        }*/

        $user->Cash = TAccountCashMst::where("UserNo", $user->USN)->sum("Cash") ?? 0;

        if ($this->isARole($user->AUTHORITY_LEV)) {
            \Helper::web_createUserSession($request, $user->toArray(), [
                "A_TOKEN" => encrypt($user->USER_ID)
            ]);
        } else {
            \Helper::web_createUserSession($request, $user->toArray());
        }
        if ($returnUrl) {
            return redirect()->to($returnUrl);
        }

        return redirect()->route("auth.complete-data");
    }

    public function doCompleteLogin (Request $request)
    {
        if ($this->isAuthenticated())
        {
            \Validator::make($request->all(), [
                "name" =>       "sometimes|required",
                "last_name" =>  "sometimes|required",
                "phone" =>      "sometimes|required|numeric",
                "sec" =>        "sometimes|required",
                "sec_ans" =>    "sometimes|required",
                "missingData" => "required"
            ])->validate();

            // check again if user have missing data
            if (!$request->input("missingData")) {
                return redirect()->home();
            }

            try {
                $member = CF_MEMBER::where("USN", $this->user_data->USN)->firstOrFail();
            } catch (ModelNotFoundException $e) {
                return redirect()->route("auth.login")->withError(__("responses.Common.UserNotFound"));
            }

            if ($request->input("name", false)) {
                $member->NAME = $request->input("name");
            }

            if ($request->input("last_name", false)) {
                $member->SURNAME = $request->input("last_name");
            }

            if ($request->input("phone", false)) {
                $member->PHONE = $request->input("phone");
            }

            if ($request->input("sec", false)) {
                $member->SEC_QUESTION = $request->input("sec");
            }

            if ($request->input("sec_ans", false)) {
                $member->SEC_ANSWER = $request->input("sec_ans");
            }

            if ($member->save()) {
                return redirect()->home()->withSuccess(__("responses.Common.YourAccountUpdated"));
            }
        }

        return redirect()->route("auth.login");
    }

    public function doRecoveryPwd (Request $request)
    {
        \Validator::make($request->post(), [
            "emailUser" => "bail|required"
        ])->validate();

        $emailUser = $request->input('emailUser');
        $user = CF_MEMBER::where("E_MAIL", $emailUser)->orWhere("USER_ID", $emailUser)->first(["USN", "E_MAIL", "USER_ID"]);
        if ($user != null)
        {
            $pwd_token = md5($emailUser . env("APP_SALT"));
            $result = \Helper::db_execStoredProcedure("cf_game", "PROC_WEB_USER_INFO_UPD", "?, ?, ?", "@p_Result", [
                $user->USER_ID, $pwd_token, 'R'
            ]);

            switch ($result)
            {
                case 0: {
                    \Mail::to($user->E_MAIL)->send(new RecoveryPassword($user->USER_ID, $pwd_token));
                    return redirect()->back()->withSuccess(__("responses.LoginController.RecoverEmailSent"));
                }
                case -1: {
                    \Log::error("[Recovery] This account cannot be found: " . $emailUser);
                    return redirect()->back()->withError(__("responses.Common.YourAccountNotFound"));
                }
                case -2:
                default: {
                    return redirect()->back()->withError(__("responses.Common.UnknownErrorOccured"));
                }
            }
        }

        //
        \Log::error("[Recovery] This account cannot be found: " . $emailUser);
        return redirect()->back()->withFatal(__("responses.Common.YourAccountNotFound"));
    }

    public function doRecoveryPwdConfirm (Request $request, $token)
    {
        try {
            $user = CF_MEMBER::where("PASS_RECOVER_TOKEN", $token)->firstOrFail(["USER_ID", "EMAIL_VERIFY_YN", "PASS_RECOVER_TOKEN", "TOKEN_GEN_DATE", "SEC_QUESTION", "SEC_ANSWER"]);
        } catch (ModelNotFoundException $e) {
            return redirect()->back()->withError(__("responses.Common.YourAccountNotFound"));
        }

        \Validator::make($request->post(), [
            "sec" => "sometimes|required",
            "sec_ans" => "sometimes|required",
            "password" => "required",
            "password_confirmation" => "required|same:password"
        ])->validate();

        if ($user->EMAIL_VERIFY_YN == 'N') {
            return redirect()->back()->withError(__("responses.LoginController.RecoverEmailNotConfirmed"));
        }

        if (!is_null($user->SEC_ANSWER))
        {
            $sec_id = $request->input('sec');
            $sec_ans = $request->input('sec_ans');
            if ($user->SEC_QUESTION != $sec_id) {
                return redirect()->back()->withError(__("responses.Common.WrongSecretQuestion"));
            }

            if (strcmp($user->SEC_ANSWER, $sec_ans) != 0) {
                return redirect()->back()->withError(__("responses.Common.WrongSecretAnswer"));
            }
        }

        $password = $request->input('password');
        $result = \Helper::db_execStoredProcedure("cf_game", "PROC_WEB_USER_INFO_UPD", "?, ?, ?", "@p_Result", [
            $user->USER_ID, \Hash::make($password), 'W'
        ]);
        switch ($result)
        {
            case 0: {
                return redirect()->route("auth.login")->withSuccess(__("responses.LoginController.RecoverSuccessMsg"));
            }
            case -1: {
                return view('auth.forgot-password-complete')->with([
                    "title" => __("responses.Common.WrongOrError"),
                    "msg" => __("responses.Common.YourAccountNotFound")
                ]);
            }
            case -2: {
                return view('auth.forgot-password-complete')->with([
                    "title" => __("responses.Common.WrongOrError"),
                    "msg" => __("responses.Common.UnknownErrorOccured")
                ]);
            }
            default: {
                \Log::error("recoveryPwdConfirm : result=" . $result);
                return redirect()->back()->withError(__("responses.Common.UnknownErrorOccured"));
            }
        }
    }

    ///
    /// private
    ///

    private function doCreateForumAccount($user)
    {
        try {
            $preRegisterInfo = CF_WEB_FORUM_REGISTER::where("USER_ID", $user->USER_ID)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            return view("errors.others")->with([
                "error" => true,
                "msg" => __("responses.LoginController.CannotFindPreRegister")
            ]);
        }

        $salt = \Helper::web_forumGenerateSalt();
        $nowTS = now()->setTimezone(env("WEB_TIMEZONE"))->getTimestamp();

        $forumUser = new mybb_users;
        $forumUser->USN = $user->USN;
        $forumUser->USER_ID = $user->USER_ID;
        $forumUser->username = $preRegisterInfo->USER_NICK;
        $forumUser->loginname = $user->USER_ID;
        $forumUser->password = md5(md5($salt) . md5(decrypt($preRegisterInfo->USER_PASS_RSA)));
        $forumUser->salt = $salt;
        $forumUser->loginkey = \Helper::web_forumGenerateLoginKey();
        $forumUser->email = $preRegisterInfo->USER_EMAIL;
        $forumUser->usergroup = config("forum.user.group");
        $forumUser->regdate = $nowTS;
        $forumUser->website = config("app.url", env("APP_URL"));
        $forumUser->signature = config("forum.user.signature", env("APP_NAME"));
        $forumUser->allownotices = 1;
        $forumUser->hideemail = 1;
        $forumUser->receivepms = 1;
        $forumUser->pmnotice = 1;
        $forumUser->pmnotify = 1;
        $forumUser->threadmode = "linear";
        $forumUser->showimages = 1;
        $forumUser->showvideos = 1;
        $forumUser->showsigs = 1;
        $forumUser->showavatars = 1;
        $forumUser->showquickreply = 1;
        $forumUser->showredirect = 1;
        $forumUser->dateformat = config("forum.datetime.date", 5);
        $forumUser->timeformat = config("forum.datetime.time", 2);
        $forumUser->timezone = config("forum.timezone");
        $forumUser->dst = 0;
        $forumUser->dstcorrection = config("forum.dst");
        $forumUser->regip = ''; // $request->getClientIp();
        $forumUser->buddylist = '';
        $forumUser->ignorelist = '';
        $forumUser->pmfolders = '';
        $forumUser->notepad = '';
        $forumUser->usernotes = '';
        return $forumUser->save();
    }
}
