<?php

namespace App\Http\Controllers;

use App\Http\Requests\AddPackageRequest;
use App\Http\Requests\AddProfileRequest;
use App\Http\Requests\CreateAccountRequest;
use App\Http\Requests\CustomerProfileRequest;
use App\Http\Requests\MakePaymentRequest;
use App\Http\Requests\SetCreditReportRequest;
use App\Http\Requests\CreateCustomerRequest;
use App\Http\Requests\EmployeeRegistrationRequest;
use App\Models\Creditreport;
use App\Models\Module;
use App\Models\Permission;
use App\Models\Recurring;
use App\Models\Sale;
use App\Models\SecurityQuestion;
use App\Models\User;
use App\Models\UserIdentityQuestionAnswer;
use App\Models\UserSecurityQuestion;
use App\Models\UserSecurityQuestionAnswer;
use App\Services\CreditReportService;
use App\Services\CustomContainer;
use App\Services\Package;
use App\Services\Payment\GateWay;
use App\Services\Payment\Payment;
use App\Services\Register;
use App\Services\SmartCredit\SmartCredit;
use App\Services\UploadMedia;
use App\Traits\ApiResponseTrait;
use App\Utility\Email;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Http\Requests\ClientRegistration;


class RegisterController extends Controller
{
    use ApiResponseTrait;

    public $data = [];
    public string $message = 'Failed';
    public string $status_code = '';
    public string $type = 'error';
    public string $code = '';

    public function __construct()
    {
        $this->status_code = config('constant.API_FAILED_CODE');
    }
    public function createAccount(Request $request)
    {
        return view('client.manual_client_create');
    }
    public function createManualAccount(ClientRegistration $request)
    {
        $inputData = $request->all();
        $do_next_step = true;
        $this->code = config('constant.API_FAILED_CODE');
        $logData['action'] = "CREATE_ACCOUNT_MANUALLY";
        $last_payment_date = getCurrentDateTime();
        $user_access_date = getStringToDateTime($inputData['user_access_date']);
        $data = [];
        if(isset($inputData['make_payment']) && $inputData['make_payment']) {
            $recurringResponse = (new Package())->recurringPackage($inputData);
            $this->message = $recurringResponse['message'];
            $do_next_step  = $recurringResponse['status'];
            $last_payment_date = getStringToDateTime($inputData['payment_date']);
            $user_access_date = getDateAfterSpicificDay($last_payment_date,config('constant.PAYMENT_INTERVAL_DAY'));
        }
        if($do_next_step) {
            try {
                DB::beginTransaction();
                $inputData['wave'] = 1;
                $inputData['subscription_status'] = 1;
                $inputData['last_payment_date'] = $last_payment_date;
                $inputData['user_access_end_date'] = $user_access_date;
                $inputData['credit_report_company_type'] = $inputData['source_type'];
                if (!$data = (new Register())->createAccount($inputData)) {
                    throw new \Exception("Account creation failed.Please try again!");
                }

                if (isset($data['id']) && $data['id'] > 0) {
                    $creditReportData['user_id'] = $data['id'];
                    $creditReportData['email'] = $inputData['email'];
                    $creditReportData['password'] = $inputData['password'];
                    $creditReportData['report_type'] = $inputData['source_type'];

                    (new Creditreport())->insertCreditReport($creditReportData);
                    if(isset($inputData['make_payment']) && $inputData['make_payment']) {
                        $recurringData['user_id'] = $data['id'];
                        $recurringData['email'] = $inputData['email'];
                        (new Recurring())->updateByEmail($recurringData);
                    }
                }

                $this->message = "Account created successfully.";
                $this->code = config('constant.API_SUCCESS_CODE');
                $this->type = 'success';

                DB::commit();
            } catch (\Exception $ex) {
                DB::rollback();
                $this->message = $ex->getMessage();

            }
        }

        appLog($this->logDataCreate($logData, $this->prepareInputLog($inputData), $this->message, '', $this->code));

        return back()->with([$this->type => $this->message]);
    }

    public function addProfile(AddProfileRequest $request)
    {

        $logData['action'] = "PROFILE_ADD";
        $inputData = $request->all();

        $data = [];
        try {

            DB::beginTransaction();

            $user_id = getUserId();

            if (!(new Register())->addProfile($inputData, $user_id)) {
                throw new \Exception("Profile update failed.Please try again!");
            }

            DB::commit();

            $message = "Profile updated successfully.";
            $code = config('constant.API_SUCCESS_CODE');
            $data = $inputData;

        } catch (\Exception $ex) {
            DB::rollback();
            $message = $ex->getMessage();
            $code = config('constant.API_FAILED_CODE');
        }

        appLog($this->logDataCreate($logData, $inputData, $message, $data, $code));

        return $this->sendApiResponse(
            $data,
            $message,
            $code
        );
    }

    public function addPackage(AddPackageRequest $request)
    {
        $logData['action'] = "PACKAGE_ADD";
        $inputData = $request->all();
        $data = [];
        try {

            DB::beginTransaction();

            $user_id = getUserId();

            if (!(new Register())->addPackage($inputData, $user_id)) {
                throw new \Exception("Package added failed.Please try again!");
            }

            DB::commit();

            $message = "Package added successfully.";
            $code = config('constant.API_SUCCESS_CODE');
            $data = $inputData;

        } catch (\Exception $ex) {
            DB::rollback();
            $message = $ex->getMessage();
            $code = config('constant.API_FAILED_CODE');
        }
        appLog($this->logDataCreate($logData, $inputData, $message, $data, $code));
        return $this->sendApiResponse(
            $data,
            $message,
            $code
        );
    }

    public function importCreditReportForUser(SetCreditReportRequest $request)
    {

        $logData['action'] = "IMPORT_CREDIT_REPORT";

        $inputData = $request->all();

        try {

            $package_id = $inputData['package_id'];
            $user_id = getUserId();

            DB::beginTransaction();

            $message = "Report not found";

            $creditReport = new CreditReportService();

            if (!(new Register())->addPackage($package_id, $user_id)) {
                throw new \Exception("Package added failed.Please try again!");
            }

            $response = $creditReport->getSmartCreditHTML($inputData['email'], $inputData['password']);

            if (!$response['status']) {
                throw new \Exception($message);
            }

            $creditReportObj = app(\App\Models\Creditreport::class);

            $credit_reportData['user_id'] = $user_id;
            $credit_reportData['html_content'] = $response['html'];

            if (!$creditReportObj->addOrUpdateCreditReport($credit_reportData)) {
                throw new \Exception("Report upload problem.");
            }

            $message = "Your report has been saved successfully";
            $code = config('constant.API_SUCCESS_CODE');

            DB::commit();

        } catch (\Exception $ex) {
            DB::rollback();
            $message = $ex->getMessage();
            $code = config('constant.API_FAILED_CODE');
        }

        appLog($this->logDataCreate($logData, $inputData, $message, $inputData, $code));

        return $this->sendApiResponse(
            [],
            $message,
            $code
        );
    }

    public function getUserInfoById()
    {
        $logData['action'] = "GET_USER_INFO_BY_ID";
        $userObj = app(User::class);

        $user_id = getUserId();

        $userData = $userObj->getUserByUserId($user_id);
        $security_questions = (new SecurityQuestion())->getSecurityQuestion();
        $userData->password = customDecrypt($userData->password);
        $message = "User not found";
        $code = config('constant.API_FAILED_CODE');
        $userData['questionList'] = $security_questions;
        if (!empty($userData)) {
            $message = "User info fetched successfully";
            $code = config('constant.API_SUCCESS_CODE');
        }
        appLog($this->logDataCreate($logData, $user_id, $message, $userData, $code));
        return $this->sendApiResponse(
            $userData,
            $message,
            $code
        );
    }

    private function prepareQuestionAnswer(&$data)
    {

        $questionArray = $data['questionList']['questionAnswer'];
        unset($data['questionList']['questionAnswer']);
        //$selected_questions = $data['questionList'];
        //dd($questionArray['idVerificationCriteria']['question1']['choiceList']['choice'],$selected_questions['answer1']);
        $question1 = $questionArray['idVerificationCriteria']['question1']['choiceList']['choice'];
        $question2 = $questionArray['idVerificationCriteria']['question2']['choiceList']['choice'];
        $question3 = $questionArray['idVerificationCriteria']['question3']['choiceList']['choice'];

        if (!empty($question1)) {
            foreach ($question1 as $q1) {
                if (isset($q1['key']) && $q1['key'] == $data['questionList']['answer1']) {
                    $data['questionList']['answer1'] = $q1['display'];
                }
            }
        }

        if (!empty($question2)) {
            foreach ($question2 as $q2) {
                if (isset($q2['key']) && $q2['key'] == $data['questionList']['answer2']) {
                    $data['questionList']['answer2'] = $q2['display'];
                }
            }
        }

        if (!empty($question3)) {
            foreach ($question3 as $q3) {
                if (isset($q3['key']) && $q3['key'] == $data['questionList']['answer3']) {
                    $data['questionList']['answer3'] = $q1['display'];
                }
            }
        }

    }

    public function makePaymentByUser(MakePaymentRequest $request): JsonResponse
    {
        $logData['action'] = "MAKE_PAYMENT_START";

        $message = "Unknown error occurred.";
        $status_code = config('constant.API_FAILED_CODE');

        $inputData = $request->all();
        $userData = (new Register())->emailVarification($inputData['email']);

        if (!empty($userData)) {
            try {

                $user_id = $userData['id'];
                $inputData['user_id'] = $user_id;
                $inputData['amount'] = config('constant.PLAN_AMOUNT');
                $package = (new Package());
                $package->makePayment($inputData);
                if ($package->status_code == config('constant.API_SUCCESS_CODE')) {
                    $inputData['email'] = $userData['email'];
                    $inputData['name'] = $userData['first_name'] . ' ' . $userData['last_name'];
                    $this->paymentMail($inputData);
                }
                $message = "Successfully Saved.";
                $status_code = config('constant.API_SUCCESS_CODE');

                Auth::loginUsingId($user_id);

            } catch (\Exception $ex) {
                $logData['exception']['message'] = $ex->getMessage();
                $logData['exception']['trace'] = $ex->getTraceAsString();
            }

            $this->data = $userData;
            $this->message = $message;
            $this->status_code = $status_code;
        }
        appLog($this->logDataCreate($logData, $this->prepareInputLog($inputData), $this->message, $this->prepareInputLog($this->data), $this->status_code));
        return $this->sendApiResponse(
            $this->data,
            $this->message,
            $this->status_code
        );
    }

    public function makePayment(Request $request): JsonResponse
    {
        $postData = $request->all();
        $logData['action'] = "MAKE_PAYMENT_START";
        $data = [];
        $message = '';
        $status_code = config('constant.API_FAILED_CODE');
        $userData = (new User())->getUserByEmail($postData['email']);
        if (!empty($userData)) {
            $user_question_answer = (new UserSecurityQuestionAnswer())->getUserSecurityQuestionAnswer($userData['id']);

            $inputData = [];
            $inputData['id'] = $userData['id'];
            $inputData["first_name"] = $userData["first_name"];
            $inputData["last_name"] = $userData["last_name"];
            $inputData['answer'] = $user_question_answer['answer'] ?? "";
            $inputData['question_id'] = $user_question_answer['question_id'] ?? 1;
            $inputData["email"] = $userData["email"];
            $inputData["password"] = customDecrypt($userData["password"]);
            $inputData["street_no"] = $userData["street_no"];
            $inputData["street_name"] = $userData["street_name"];
            $inputData["city"] = $userData["city"];
            $inputData["state"] = $userData["state"];
            $inputData["birth_date"] = $userData["birth_date"];
            $inputData["ssn"] = $userData["ssn"];
            $inputData['card_number'] = $postData['card_number'];
            $inputData['expiry'] = $postData['expiry'];
            $inputData["amount"] = $postData["amount"];
            $inputData['package_id'] = "2";
            $inputData["full_ssn"] = $postData["full_ssn"];
            $inputData["phone"] = $postData["phone"];
            $inputData["zip_code"] = $postData["zip_code"];

            $package = (new Package());
            $package->purchasePackage($inputData);
            if ($package->status_code == config('constant.API_SUCCESS_CODE')) {
                Auth::loginUsingId($userData['id']);
            }
            $data = $package->data;
            $message = $package->message;
            $status_code = config('constant.API_SUCCESS_CODE');
            appLog($this->logDataCreate($logData, $postData, $message, $data, $status_code));
        }
        return $this->sendApiResponse(
            $data,
            $message,
            $status_code
        );
    }

    public function emailVerification(CreateAccountRequest $request)
    {
        $logData['action'] = "EMAIL_VERIFICATION";
        $inputData = $request->all();
        $this->data = [];
        $this->message = '';
        $this->status_code = config('constant.API_SUCCESS_CODE');

        $result = [];

        if(config('app.REPORT_PROVIDER') == '3') {
            $result = (new Package())->checkIsEmailExistOnSmartCredit($inputData);
        }
//        elseif (config('app.REPORT_PROVIDER') == '2'){
//            $result = $this->identityIQemailVerification();
//        }

        if (isset($result['status']) && $result['status']) {
            $this->status_code = config('constant.API_FAILED_CODE');
            $this->message = $result['message'];
        }

        return $this->sendApiResponse(
            $this->data,
            $this->message,
            $this->status_code
        );
    }
    private function identityIQemailVerification()
    {
        $result['status'] = true;
        $result['message'] = "You already have an account with identityIQ";
        return $result;
    }
    public function profileVerification(CustomerProfileRequest $request)
    {

        $logData['action'] = "SSN_VERIFICATION";

        $inputData = $request->all();
        $this->data = [];
        $this->message = '';

        $this->status_code = config('constant.API_SUCCESS_CODE');

        $smartCreditRequestData['ssn'] = $inputData['full_ssn'];
        $smartCreditRequestData['email'] = $inputData['email'];

        $result =[];
        if(config('app.REPORT_PROVIDER') == '3') {
            $result = (new SmartCredit(config('app.CLIENT_KEY')))
                ->setData($smartCreditRequestData)
                ->checkIsSsnExistOnSmartCredit();
        }
//        elseif (config('app.REPORT_PROVIDER') == '2'){
//            $result = $this->identityIQemailVerification();
//        }

        if (isset($result['status']) && $result['status']) {
            $this->status_code = config('constant.API_FAILED_CODE');
            $this->message = $result['message'];
        }

        return $this->sendApiResponse(
            $this->data,
            $this->message,
            $this->status_code
        );
    }

    public function getSecurityQuestion(Request $request): JsonResponse
    {
        $logData['action'] = "GET_SECURITY_QUESTION";
        $questions = (new package())->securityQuestions();
        return $this->sendApiResponse(
            $questions->data,
            $questions->message,
            $questions->status_code
        );
    }

    public function createCustomer(CreateCustomerRequest $request): JsonResponse
    {

        $logData['action'] = "CREATE_CUSTOMER_START";
        appLog($logData);

        $inputData = $request->all();
        $package = (new Package());

        if($request['is_free'] != 1) {
            $package->createCustomer($inputData);
        }

        $this->message = $package->message;
        $this->status_code = $package->status_code;

        $payment_status_code = $package->payment_status_code;
        $is_success_payment = $payment_status_code == config('constant.API_SUCCESS_CODE');

        if ($is_success_payment || $request['is_free'] == 1) {

            // if free customer then status inactive for customer
//            if ($request['is_free'] == 1) {
//                $inputData['status'] = 2;  // status = 2 for inactive user, 1 for active
//            }

            // Insert User table
            $inputData['credit_report_company_type'] = config('app.REPORT_PROVIDER') ?? 3;
            $userData = $this->addUser($inputData);

            $inputData['user_id'] = $userData['id'];
            $inputData['status_code'] = $payment_status_code;
            $inputData['is_free'] = $request['is_free'];
            // insert credit report table and user update
            $package->purchasePackage($inputData);

            // update sale table by order_id for success payment
            if(isset($package->data['order_id']) && $package->data['order_id']>0 && $request['is_free'] != 1) {
                (new Sale())->updateByOrderId($package->data['order_id'], ['user_id' => $userData['id']]);
            }

            // update recurring table by user_id for success payment
            if($request['is_free'] != 1) {
                (new Recurring())->updateByEmail($inputData);
            }

            // Sent email to customer
            $mailData['email'] = $inputData['email'];
            $mailData['name'] = $inputData['first_name'] . ' ' . $inputData['last_name'];
            if($request['is_free'] != 1) {
                $this->paymentMail($mailData);
            }
            setSession('isFree',0);
        }

        $this->data = [
            'tracking_token' => $package->tracking_token,
            'customer_token' => $package->customer_token,
            'questionAnswer' => $package->data
        ];

        $logData['action'] =  "CREATE_CUSTOMER_END";
        appLog($logData);

        return $this->sendApiResponse(
            $this->data,
            $this->message,
            $this->status_code
        );
    }

    public function getIdentityQuestionAnswer(Request $request): JsonResponse
    {
        $logData['action'] = "GET_IDENTITY_QUESTION_ANSWER";
        $questions = (new package())->identityQuestionAnswer();
        return $this->sendApiResponse(
            $questions['data']['idVerificationCriteria'],
            $questions['message'],
            $questions['status_code']
        );
    }

    public function postIdentityQuestion(Request $request): JsonResponse
    {
        $inputData = $request->all();
        $questions = (new package())->submitIdentityQuestionAnswer($inputData);
        if ($questions->status_code == config('constant.API_SUCCESS_CODE')) {
            $questions->data = $this->insertSecurityQuestionAnswer($inputData);
        }
        return $this->sendApiResponse(
            $questions->data,
            $questions->message,
            $questions->status_code
        );
    }

    private function insertSecurityQuestionAnswer($inputData)
    {
        $userQuestion = [];
        $logData['action'] = "INSERT_USER_IDENTITY_QUESTION_ANSWER";
        $userData = (new Register())->emailVarification($inputData['email']);
        if (!empty($userData)) {
            $userQuestion = ['user_id' => $userData['id'], 'data' => $inputData['security_question_answer']];
            (new UserIdentityQuestionAnswer())->insertData($userQuestion);
            $this->status_code = config('constant.API_SUCCESS_CODE');
            $this->message = 'successfully inserted user identity question answer';
        }
        appLog($this->logDataCreate($logData, $userQuestion, $this->message, $this->data, $this->status_code));
        return $userData;
    }

    public function insertEmployee(EmployeeRegistrationRequest $request)
    {
        $inputData = $request->all();
        $inputData['user_type'] = 2;
        $userData = $this->addUser($inputData);
        if (!empty($userData)) {
            $inputData['employee_id'] = $userData['id'];
            (new Permission())->insertUserPermission($inputData);
        }
        return back()->with([$this->type => $this->message]);
    }

    private function addUser($inputData)
    {
        $logData['action'] = "CREATE_ACCOUNT";
        $this->data = [];
        try {
            DB::beginTransaction();
            if (!$this->data = (new Register())->createAccount($inputData)) {
                throw new \Exception("Account creation failed.Please try again!");
            }
            $this->message = "Account created successfully.";
            $this->type = 'success';
            $this->status_code = config('constant.API_SUCCESS_CODE');
            DB::commit();
        } catch (\Exception $ex) {
            DB::rollback();
            $this->message = $ex->getMessage();
            $this->status_code = config('constant.API_FAILED_CODE');
        }

        appLog($this->logDataCreate($logData, $this->prepareInputLog($inputData), $this->message, $this->prepareInputLog($this->data), $this->status_code));

        return $this->data;
    }

    private function prepareInputLog($inputData)
    {
        if (!empty($inputData['password'])) {
            $inputData['password'] = "*********";
        }
        if (!empty($inputData['full_ssn'])) {
            $inputData['full_ssn'] = "*********";
        }
        if (!empty($inputData['security_key'])) {
            $inputData['security_key'] = "*********";
        }
        if (!empty($inputData['card_number'])) {
            $inputData['card_number'] = creditCardNumberMasking($inputData['card_number']);
        }

        return $inputData;
    }

    private function logDataCreate($logData, $request, $message, $response, $code)
    {
        $logData['data']['request'] = $request;
        $logData['data']['message'] = $message;
        $logData['data']['response'] = $response;
        $logData['data']['code'] = $code;
        return $logData;
    }

    private function paymentMail($inputData)
    {
        $data['email'] = $inputData['email'];
        $data['email_body'] = $inputData['name'];
        $data['email_subject'] = "[Your Purchase is Ready] Credit Zombies";
        $from = null;
        $attachment = null;
        (new Email())->send($data, $data['email_subject'], $from, $attachment, 'email.payment_success_letter', $data['email']);
    }

}
