<?php

namespace App\Http\Controllers\Frontend;

use App\Models\CSRNow\UserAddress;
use App\Models\PasswordReset;
use App\Models\UserSetting;
use App\Notifications\OTPVerificationNotification;
use App\Notifications\ResetPasswordNotification;
use Google2FA;
use Carbon\Carbon;
use App\Services\Export;
use App\Mail\ChangeEmail;
use App\Jobs\SendEmailJob;
use App\Mail\OldChangeEmail;
use Illuminate\Http\Request;
use App\Jobs\Export as JobExport;
use Illuminate\Contracts\View\View;
use App\Http\Controllers\Controller;
use App\Models\ApiSettings;
use App\Models\CSRNow\City;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\Notification;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use PragmaRX\Google2FA\Exceptions\InvalidCharactersException;
use PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException;
use PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException;
use App\Models\CSRNow\Country;
use App\Models\CSRNow\Language as CSRNowLanguage;
use App\Models\CSRNow\State;
use App\Models\IdentifyVerification;
use App\Models\Member;
use App\Models\User;
use DateTime;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use function PHPUnit\Framework\isFalse;

class ProfileController extends Controller
{
    /**
     * @throws IncompatibleWithGoogleAuthenticatorException
     * @throws SecretKeyTooShortException
     * @throws InvalidCharactersException
     */
    public function profile()
    {
        $key = Google2FA::generateSecretKey();
        $qr = Google2FA::getQRCodeUrl(
            config("app.name"),
            Auth::user()->details->email,
            $key
        );
        $selectedRole = Session::get('login_user_role');
        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->get(config('csrnow.api.live_endpoint').'auth/profile');
        $user = $data->object()->data ?? null;
        $dateOfBirth = $user->date_of_birth ?? ''; // Default value or old input
        $dobParts = explode('-', $dateOfBirth);
        $dobYear = $dobParts[0] ?? '';
        $dobMonth = $dobParts[1] ?? '';
        $dobDay = $dobParts[2] ?? '';
        $userCountryPhoneCode = Country::where('id',$user->country_id)->selectRaw("IF(LEFT(phonecode, 1) = '+', phonecode, CONCAT('+', phonecode)) as phonecode")->pluck('phonecode')->first();

        $country = Country::get();
        $language = CSRNowLanguage::where('status',1)->get();
        $timeZones = \DateTimeZone::listIdentifiers(\DateTimeZone::ALL);
        $timeZoneWithOffsets = [];
        $utcDate = Carbon::now('UTC');
        foreach ($timeZones as $tz) {
            $dateTimeZone = new \DateTimeZone($tz);
            $offsetInSeconds = $dateTimeZone->getOffset($utcDate);

            // Convert offset to hours and minutes
            $hours = (int)($offsetInSeconds / 3600);
            $minutes = abs((int)(($offsetInSeconds % 3600) / 60));

            $sign = $hours < 0 ? '-' : '+';

            // Format the offset
            $formattedOffset = '(GMT '.$sign .' '. abs($hours) . ':' . str_pad($minutes, 2, '0', STR_PAD_LEFT).')';

            $timeZoneWithOffsets[] = [
                'timezone' => $tz,
                'formattedTimezone' => $formattedOffset.' '. $tz,
            ];
        }
        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->get(config('csrnow.api.live_endpoint').'auth/user-company');
        $userCompany = $data->object()->data ?? null;

        if (Auth::user()->setting->new_temp_email === $user->email){
            Auth::user()->setting->new_temp_email = null;
            UserSetting::where('user_id',Auth::id())->update(['new_temp_email' => null]);
        }
        $member = Auth::user()->member;
        return view('frontend.profile.index', compact('key', 'qr', 'selectedRole','user','country','language','timeZoneWithOffsets','member','dobYear','dobMonth','dobDay','userCountryPhoneCode','userCompany'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param Request $request
     * @param int $id
     * @return JsonResponse|RedirectResponse
     * @throws ValidationException
     */
    public function update($id, Request $request)
    {
        if (readOnlyMode()) {
            return response()->json(['success' => false, 'message' => 'Feature disabled whilst in switched user mode.', 'data' => []]);
        }
        $id = basicDecrypt($id);
        $hasStates = State::where('country_id', $request->country_id)->exists();
        $stateRequired = $hasStates ? 'required' : 'nullable';

        $validationRule = [
            'first_name' => ['required','max:255','alpha_dash_spaces'],
            'last_name' => ['required','max:255','alpha_dash_spaces'],
            'address_1' => 'nullable|address_ctm|max:30',
            'address_2' => 'nullable|address_ctm|max:30',
            'country_id' => 'required',
            'state_id' => [$stateRequired],
            'postal_code' => 'nullable|max:10|alpha_num_dash_spaces',
            'language_id' => 'nullable',
            'timezone' => 'sometimes',
            'day' => ['required_with_all:month,year'],
            'month' => ['required_with_all:day,year',],
            'year' => ['required_with_all:day,year','digits:4',],
        ];
        $messages = [
            'first_name.required' => 'The First Name field is required.',
            'first_name.max' => 'The First Name may not be greater than 255 characters.',

            'last_name.required' => 'The Last Name field is required.',
            'last_name.max' => 'The Last Name may not be greater than 255 characters.',

            'address_1.max' => 'The Address Line 1 may not be greater than 30 characters.',
            'address_2.max' => 'The Address Line 2 may not be greater than 30 characters.',

            'country_id.required' => 'The Country field is required.',
            'state_id.required' => 'The Region / State / Province field is required.',

            'postal_code.max' => 'The Postal Code may not be greater than 10 characters.',

            'day.required_with_all' => 'The Day field is required.',
            'month.required_with_all' => 'The Month field is required.',
            'year.required_with_all' => 'The Year field is required.',
            'year.digits' => 'The Year must be exactly 4 digits.',

            'phone.regex' => 'The Phone field must be valid.',
        ];
        $validator = Validator::make($request->all(), $validationRule, $messages);

        // Group all date validation under a single message
        $validator->after(function ($validator) use ($request) {
            if (!$request->filled(['day', 'month', 'year'])) {
                $validator->errors()->add('date_of_birth', 'The Date of Birth fields are required.');
                return;
            }
            if (!preg_match('/^\d{4}$/', $request->year)) {
                $validator->errors()->add('date_of_birth', 'The Date field is required.');
                return;
            }

            $year = (int) $request->year;
            $month = (int) $request->month;
            $day = (int) $request->day;
            $currentYear = (int) date('Y');

            if ($year < 1900) {
                $validator->errors()->add('date_of_birth', 'The Year must be 1900 or later.');
                return;
            }

            if ($year > $currentYear) {
                $validator->errors()->add('date_of_birth', 'The Year cannot be in the future.');
                return;
            }

            if ($month < 1 || $month > 12) {
                $validator->errors()->add('date_of_birth', 'The Month field must be valid.');
                return;
            }

            // Ensure the day is valid (1-31)
            if ($day < 1 || $day > 31) {
                $validator->errors()->add('date_of_birth', 'The Day field must be valid.');
                return;
            }

            // Check for valid February dates based on leap year
            if ($month == 2) {
                $isLeapYear = ($year % 4 == 0 && $year % 100 != 0) || ($year % 400 == 0);
                $maxDaysInFeb = $isLeapYear ? 29 : 28;

                if ($day > $maxDaysInFeb) {
                    $validator->errors()->add('date_of_birth', "February {$year} does not have {$day} days.");
                    return;
                }
            }

            $dob = sprintf('%04d-%02d-%02d', $request->year, $request->month, $request->day);
            if (!strtotime($dob)) {
                $validator->errors()->add('date_of_birth', 'The Date of Birth must be valid.');
                return;
            }

            if (now()->diff(new DateTime($dob))->y < 18) {
                $validator->errors()->add('date_of_birth', 'You must be at least 18 years old.');
            }
        });



        if ($validator->fails()) {
            $errors = $validator->errors()->toArray();
            unset($errors['day'], $errors['month'], $errors['year']);
            $formattedErrors = [];
            foreach ($errors as $field => $messages) {
                $formattedErrors[$field] = array_unique($messages);
            }
            $firstErrorMessage = collect($formattedErrors)->flatten()->first() ?? 'Validation failed.';
            $errorCount = collect($formattedErrors)->flatten()->count();
            $response = [
                'code' => 422,
                'errors' => $formattedErrors,
                'msg' => $firstErrorMessage
            ];

            if ($errorCount > 1) {
                $response['_message'] = "{$firstErrorMessage} (and " . ($errorCount - 1) . " more error" . ($errorCount > 2 ? 's' : '') . ")";
            }
            return response()->json($response, 422);
        }

        $date_of_birth = sprintf('%04d-%02d-%02d', $request->year, $request->month, $request->day);
        $inputs['date_of_birth'] = $date_of_birth;
        $inputs['first_name'] = $request->first_name;
        $inputs['last_name'] = $request->last_name;
        $inputs['username'] = $request->username;
        $inputs['address_1'] = $request->address_1;
        $inputs['address_2'] = $request->address_2;
        $inputs['country_id'] = $request->country_id;
        $inputs['state_id'] = $request->state_id;
        $inputs['city'] = $request->city;
        $inputs['postal_code'] = $request->postal_code;
        $inputs['phone'] = $request->phone;
        $inputs['is_business_account'] = $request->is_business_account;

        $message = 'Your Profile has been updated successfully.';

        $oldUserData = Auth::user()->details;
        $oldProfileData = Auth::user()->details->profile;
        $oldAddressData = Auth::user()->details->address;

        $inputs['email'] = $oldUserData->email;
        $inputs['timezone'] = $request->timezone;

        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'auth/profile',$inputs);
        $response = $data->object();

        if (isset($response->status) && $response->status ==  true) {
            $oldName = $oldUserData->first_name . ' ' . $oldUserData->last_name;
            $response->data->name = $response->data->first_name . ' ' . $response->data->last_name;
            $newAddressData = UserAddress::where('user_id',Auth::user()->external_id)->first();

            /*---- START for log ----*/
             $needToDropKyc = false;
            if ($response->data->name != $oldName) {
                 $needToDropKyc = true;
                saveLog('User name updated from ' . $oldName . ' to ' . $response->data->name, Auth::user(), Auth::user(), 'updated');
            }

            $oldDOB = $oldProfileData->date_of_birth ?? '';
            if ($oldDOB == "0000-00-00"){
                $oldDOB = '';
            }
            if ($date_of_birth != $oldDOB){
                 $needToDropKyc = true;
                saveLog('User birth date updated from ' . (($oldDOB != '') ? $oldDOB : 'none') . ' to ' . $date_of_birth, Auth::user(), Auth::user(), 'updated');
            }

            if ($request->is_business_account != ($oldProfileData->is_business_account ?? '')){
                saveLog('User business account has been ' . ($request->is_business_account == 1 ? 'enabled' : 'disabled'), Auth::user(), Auth::user(), 'updated');
            }

            if ($request->gender != ($oldProfileData->gender ?? '')){
                saveLog('User gender updated from ' . ($oldProfileData->gender ?? 'none') . ' to ' . $request->gender, Auth::user(), Auth::user(), 'updated');
            }

            if ($request->address_1 != ($oldAddressData->address_1 ?? '')){
                 $needToDropKyc = true;
                saveLog('User Street name and house number updated from ' . ($oldAddressData->address_1 ?? 'none') . ' to ' . $request->address_1, Auth::user(), Auth::user(), 'updated');
            }

            if ($request->address_2 != ($oldAddressData->address_2 ?? '')){
                 $needToDropKyc = true;
                saveLog('User Address Line 2 updated from ' . ($oldAddressData->address_2 ?? 'none') . ' to ' . $request->address_2, Auth::user(), Auth::user(), 'updated');
            }

            if ($request->postal_code != ($oldAddressData->postal_code ?? '')){
                 $needToDropKyc = true;
                saveLog('User postal code updated from ' . ($oldAddressData->postal_code ?? 'none') . ' to ' . $request->postal_code, Auth::user(), Auth::user(), 'updated');
            }

            if ($request->country_id != ($oldAddressData->country_id ?? '')){
                 $needToDropKyc = true;
                saveLog('User country updated from ' . ($oldAddressData->country->country_name ?? 'none') . ' to ' . ($newAddressData->country->country_name ?? 'none'), Auth::user(), Auth::user(), 'updated');
            }

            if ($request->state_id != ($oldAddressData->state_id ?? '')){
                 $needToDropKyc = true;
                saveLog('User region updated from ' . ($oldAddressData->state->name ?? 'none') . ' to ' . ($newAddressData->state->name ?? 'none'), Auth::user(), Auth::user(), 'updated');
            }

            if ($request->city != ($oldAddressData->city ?? '')){
                 $needToDropKyc = true;
                saveLog('User city updated from ' . ($oldAddressData->city ?? 'none') . ' to ' . ($newAddressData->city?? 'none'), Auth::user(), Auth::user(), 'updated');
            }

            if ($request->phone != ($oldProfileData->phone ?? '')){
                saveLog('User phone number updated from ' . ($oldProfileData->phone ?? 'none') . ' to ' . ($request->phone?? 'none'), Auth::user(), Auth::user(), 'updated');
            }
            /*---- END for log ----*/

            /*---- Strat for Drop kyc ----*/
            if($needToDropKyc){
                $member = Member::where('user_id',Auth::user()->id)->first();
                if(isset($member) && $member->kyc_status == "active"){
                    $IdentityDetails = IdentifyVerification::where('user_id',Auth::user()->id)->withoutTrashed()->first();
                    if($IdentityDetails){
                        $response = shuftipro_delete_user_ref($IdentityDetails->reference,'User Resubmit KYC Form');
                        $response_data = $response->json();
                        if ($response->successful()) {
                            $successLog = 'Shufti API for delete user call successful</br>';
                            activity('Shufti API call successful')->withProperties([])->causedBy(User::orderBy('external_id','asc')->first())->performedOn(User::orderBy('external_id','asc')->first())->log($successLog);
                            //change status of kyc to drop
                            $IdentityDetails->final_status = 3;
                            $IdentityDetails->status = "dropped";
                            $IdentityDetails->save();
                            $IdentityDetails->delete();
                            Member::where('user_id',$IdentityDetails->user_id)->update(['kyc_status'=>'inactive']);
                        } else{
                            $log = 'Failed to Shufti API for delete user call because of '. ($response_data['error']['message'] ?? 'some error') . '</br>';
                            activity('Shufti API failed')->withProperties([])->causedBy(User::orderBy('external_id','asc')->first())->performedOn(User::orderBy('external_id','asc')->first())->log($log);
                            return response()->json(['success' => false, 'msg' => $response_data['error']['message'] ?? 'Some error occured']);
                        }
                    } else{
                        Member::where('user_id',Auth::user()->id)->update(['kyc_status'=>'inactive']);
                    }
                    createNotification('Your KYC/KYB Dropped','KYC/KYB verification process was dropped due to a profile update. Please review and resubmit your details.',Auth::user()->id,url('/member/identity-verification'));
                    saveLog('KYC/KYB verification process was dropped due to a profile update.', Auth::user(), ['logType' => 'identity verification'], 'identity verification');
                }
            }
            /*---- End for Drop kyc ----*/

            //timezone
            Session::put('user_timezone', $request->timezone);
            $language = CSRNowLanguage::where('id', $request->language_id)->where("status", 1)->first();
            if ($language) {
                Session::put('locale', $language->short_name);
                Session::put('locale_flag', $language->flag);
                Session::put('locale_id', $language->id);
            }

            UserSetting::updateOrCreate(['user_id' => Auth::id()],['language_id' => $request->language_id,'timezone' => $request->timezone]);

            return response()->json(['success' => true, 'message' => $message, 'data' => $inputs, 'record' => 'updated']);
        } else {
            $msg = (isset($response->message)) ? ((is_string($response->message)) ? $response->message : array_values((array) $response->message)[0][0]) : 'Getting some error.';
            return response()->json(['status' => "No", 'msg' => $msg], $data->getStatusCode());
        }
    }

    public function checkEmailPassword(Request $request){
        $request->validate([
            'new_email' => 'required|email',
            'current_password' => 'required',
        ], [
            'new_email.required'        => 'The New Email field is required.',
            'new_email.email'           => 'The Email must be a valid email address.',
            'current_password.required' => 'The Current Password field is required.',
        ]);

        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'auth/profile/check-password',['password' => $request->current_password]);
        $response = $data->object();
        if (isset($response->status) && $response->status ==  true) {
            $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'email/is-exists',['email' => $request->new_email]);
            $response = $data->object();
            if (isset($response->status) && $response->status ==  true) {
                return response()->json(['status' => true, 'message' => '']);
            }
        }
        $msg = (isset($response->message)) ? ((is_string($response->message)) ? $response->message : array_values((array) $response->message)[0][0]) : 'Getting some error.';
        return response()->json(['status' => false, 'msg' => $msg], $data->getStatusCode());
    }

    public function changeEmail(Request $request)
    {
        $request->validate([
            'new_email' => 'required|email',
            'current_password' => 'required',
            'upload_proof' => 'required_with:has_old_email_access|mimes:jpg,png,jpeg|max:10240',
        ],[
            'current_password.required' => 'The password field is required.',
            'upload_proof.required_with' => "The upload proof is required when you don't have old email access."
        ]);

        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'auth/profile/check-password',['password' => $request->current_password]);
        $response = $data->object();
        if (isset($response->status) && $response->status ==  true) {
            $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'email/is-exists',['email' => $request->new_email]);
            $response = $data->object();
            if (isset($response->status) && $response->status ==  true) {
                if($request->has_old_email_access == 1){
                    $description = 'Dear Support,'.'<br>'.
                                    'I am ' . Auth::user()->details->first_name. ' ' .Auth::user()->details->last_name .'<br>
                                    Please change my email address from '.Auth::user()->details->email .' to ' .$request->new_email.'<br><br>
                                    Date: '. Carbon::now() .'';
                    if ($request->hasFile('upload_proof')) {
                        $destinationPath = '/upload/ticket_attachment';
                        $files = uploadFileSupportAdmin($request->upload_proof,$destinationPath);
                    }
                    $apiCall = Http::withHeaders([
                        'support-access-token' => config('app.support_access_token'),
                    ])->post(
                        config('app.SUPPORT_API_ENDPOINT')."create-support-ticket",
                        array(
                            'platform' => config('app.SUPPORT_PLATFORM_NAME'),
                            'subject' => 'Change Email Request',
                            'name' => Auth::user()->details->first_name . ' ' . Auth::user()->details->last_name,
                            'email' => Auth::user()->details->email,
                            'description' => $description,
                            'category_id' => config('app.SUPPORT_CHANGE_EMAIL_CATEGORY_ID'),
                            'ip_address' => getClientIp($request),
                            'file' => $files,
                            'is_verify' => 'Yes'
                        ));
                    if ($apiCall->successful()) {
                        $response = $apiCall->object();
                        UserSetting::where('user_id',Auth::id())->update(['new_temp_email' => $request->new_email,'has_old_email_access' =>$request->has_old_email_access,'ticket_id' => $response->data->id ]);
                        $new_temp_email = $request->new_email;

                        saveLog('User request to change email from '.Auth::user()->details->email.' to '.$request->new_email,Auth::user(), Auth::user(), 'change email');
                        return response()->json(['status' => true, 'message' => 'Email change request submitted successfully.','new_email' => $new_temp_email,'resend_link' => false]);
                    }
                } else{
                    $userDetail = Auth::user()->details;

                    //Shorten Url for new email
                    $changeEmailParameter = ['id' => auth()->user()->id, 'email' => $request->new_email];
                    $expireTime = 60;
                    $changeEmailShortKey = generateRandomUrlKey($changeEmailParameter,$expireTime);
                    $changeEmailUrl = route('changeEmail',$changeEmailShortKey);

                    //Shorten Url for old email
                    $changeOldEmailParameter = ['id' => auth()->user()->id, 'email' => $userDetail->email];
                    $changeOldEmailShortKey = generateRandomUrlKey($changeOldEmailParameter,$expireTime);
                    $changeOldEmailUrl = route('changeEmail',$changeOldEmailShortKey);

                    $changeEmailDetails = [
                        'id' => auth()->user()->id,
                        'email' => $request->new_email,
                        'name' => ($userDetail->first_name ?? '')." ".($userDetail->last_name ?? ''),
                        'subject' => "Regarding change email address",
                        'role' => Session::get('login_user_role'),
                        'url' => $changeEmailUrl
                    ];

                    $changeOldEmailDetails = [
                        'id' => auth()->user()->id,
                        'email' => Auth::user()->details->email,
                        'name' => ($userDetail->first_name ?? '')." ".($userDetail->last_name ?? ''),
                        'subject' => "Regarding change email address",
                        'role' => Session::get('login_user_role'),
                        'url' => $changeOldEmailUrl
                    ];

                    $emailSwitch = getEmailSettings('change_email');
                    if ($emailSwitch == 'on') {
                        $emailClassRefNew = new ChangeEmail($changeEmailDetails);
                        SendEmailJob::dispatch($changeEmailDetails['email'], $emailClassRefNew);
                    }
                    $emailSwitch = getEmailSettings('change_old_email');
                    if($emailSwitch == 'on'){
                        $emailClassRef = new OldChangeEmail($changeOldEmailDetails);
                        SendEmailJob::dispatch(Auth::user()->details->email, $emailClassRef);
                    }
                    UserSetting::where('user_id',Auth::id())->update(['new_temp_email' => $request->new_email,'is_old_email_verified' => 0,'is_new_email_verified' => 0]);
                    $new_temp_email = $request->new_email;

                    saveLog('User request to change email from '.Auth::user()->details->email.' to '.$request->new_email,Auth::user(), Auth::user(), 'change email');

                    return response()->json(['status' => true, 'message' => 'Verification mail sent.','new_email' => $new_temp_email,'resend_link' => true]);
                }
            }
        }
        $msg = (isset($response->message)) ? ((is_string($response->message)) ? $response->message : array_values((array) $response->message)[0][0]) : 'Getting some error.';
        return response()->json(['status' => false, 'msg' => $msg], $data->getStatusCode());
    }

    public function changeEmailResendLink()
    {
        $userDetail = Auth::user()->details;
        $new_email = auth()->user()->setting->new_temp_email;
        $is_old_email_verified = auth()->user()->setting->is_old_email_verified;

        //Shorten Url for new email
        $changeEmailParameter = ['id' => auth()->user()->id, 'email' => $new_email];
        $expireTime = 60;
        //need to set flag when first request is send from admin
        if(!isset($is_old_email_verified)){
            $changeEmailParameter['is_admin_change'] = true;
        }
        $changeEmailShortKey = generateRandomUrlKey($changeEmailParameter,$expireTime);
        $changeEmailUrl = route('changeEmail',$changeEmailShortKey);

        //Shorten Url for old email
        $changeOldEmailParameter = ['id' => auth()->user()->id, 'email' => $userDetail->email];
        $changeOldEmailShortKey = generateRandomUrlKey($changeOldEmailParameter,$expireTime);
        $changeOldEmailUrl = route('changeEmail',$changeOldEmailShortKey);

        $changeEmailDetails = [
            'id' => auth()->user()->id,
            'email' => $new_email,
            'name' => ($userDetail->first_name ?? '')." ".($userDetail->last_name ?? ''),
            'subject' => "Regarding change email address",
            'role' => Session::get('login_user_role'),
            'url' => $changeEmailUrl
        ];

        $changeOldEmailDetails = [
            'id' => auth()->user()->id,
            'email' => Auth::user()->details->email,
            'name' => ($userDetail->first_name ?? '')." ".($userDetail->last_name ?? ''),
            'subject' => "Regarding change email address",
            'role' => Session::get('login_user_role'),
            'url' => $changeOldEmailUrl
        ];

        $emailSwitch = getEmailSettings('change_email');
        if ($emailSwitch == 'on') {
            $emailClassRefNew = new ChangeEmail($changeEmailDetails);
            SendEmailJob::dispatch($changeEmailDetails['email'], $emailClassRefNew);
        }
        $input['is_new_email_verified'] = 0;
        $emailSwitch = getEmailSettings('change_old_email');
        //if request by member send mail to old email also
        if (isset($is_old_email_verified)) {
            if($emailSwitch == 'on'){
                $emailClassRef = new OldChangeEmail($changeOldEmailDetails);
                SendEmailJob::dispatch(Auth::user()->details->email, $emailClassRef);
            }
            $input['is_old_email_verified'] = 0;
        }
        UserSetting::where('user_id',Auth::id())->update($input);

        saveLog('User request to resend change email link ('.$new_email.')',Auth::user(), Auth::user(), 'change email');
        $new_temp_email = $new_email;
        return response()->json(['status' => true, 'message' => 'Verification Email Sent!' ,'new_email' => $new_temp_email]);

    }

    public function changeEmailRequestCancel()
    {
        $userSetting = UserSetting::where('user_id',Auth::id())->first();
        if($userSetting->has_old_email_access == 1){
            $description = 'Dear Support,'.'<br>'.
                            'I am ' . Auth::user()->details->first_name. ' ' .Auth::user()->details->last_name .'<br>
                            I have canceled my change email request<br><br>
                            Date: '. Carbon::now() .'';

            $apiCall = Http::withHeaders([
                'support-access-token' => config('app.support_access_token'),
            ])->post(
                config('app.SUPPORT_API_ENDPOINT')."add-support-ticket-response/".$userSetting->ticket_id,
                array(
                    'description' => $description,
                ));
            $response = $apiCall->object();
            $userSetting->has_old_email_access = null;
            $userSetting->ticket_id = null;
            if(isset($response->status) && $response->status ==  false){
                return response()->json(['status' => false, 'message' => 'Getting some error.']);
            }
        }
        saveLog('User cancel change email request ('.$userSetting->new_temp_email.')',Auth::user(), Auth::user(), 'change email');
        $userSetting->new_temp_email = null;
        $userSetting->is_old_email_verified = null;
        $userSetting->is_new_email_verified = null;
        $userSetting->save();
        return response()->json(['status' => true, 'message' => 'Change email request canceled Successfully.']);

    }

    public function changePassword(Request $request)
    {
        $request->validate([
            'current_password' => 'required'
            ]
            , [
                'current_password.required' => 'The Current Password field is required.',
            ]);

        $data = Http::withToken('Bearer '.Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint').'auth/profile/check-password',['password' => $request->current_password]);
        $response = $data->object();
        if (isset($response->status) && $response->status ==  true) {
            $user = Auth::user()->details;
            PasswordReset::where('email', $request->email)->delete();
            $token = generateRandomCode(20);
            PasswordReset::create([
                'email' => $user->email,
                'token' => Hash::make($token),
            ])->token;
            //Shorten Url
            $parameter = ['token' => $token, 'email' => $user->email];
            $expireTime = 60;
            $shortKey = generateRandomUrlKey($parameter,$expireTime);
            $url = route('member.password.reset',$shortKey);
            $data = [
                'name' => $user->first_name." ".$user->last_name,
                'url' => $url
            ];
            Notification::route('mail', $user->email)->notify(new ResetPasswordNotification($data));

            saveLog('User request to change password', Auth::user(), Auth::user(), 'change password');
            return response()->json(['status' => true, 'message' => 'Password reset requested. Check your email for instructions to reset your password.']);
        } else {
            $msg = (isset($response->message)) ? ((is_string($response->message)) ? $response->message : array_values((array) $response->message)[0][0]) : 'Getting some error.';
            return response()->json(['status' => "No", 'msg' => $msg], $data->getStatusCode());
        }
    }

    public function securityIndex()
    {
        if (isset(Auth::user()->setting->old_google_auth_key) && !empty(Auth::user()->setting->old_google_auth_key)){
            $key = Auth::user()->setting->old_google_auth_key;
        } else {
            $key = Google2FA::generateSecretKey();
        }
        $qr = Google2FA::getQRCodeUrl(
            config("app.name"),
            Auth::user()->details->email,
            $key
        );
        return view('frontend.profile.security',compact('key', 'qr'));
    }

    public function OneTimePasscodeIndex()
    {
        $htmlContent = view('frontend.profile.one-time-passcode')->render();

        return response()->json(['status' => true, 'message' => '' ,'htmlContent' => $htmlContent]);
    }

    public function OneTimePasscodeEnable(Request $request)
    {
        if (empty(Auth::user()->setting->fa3_setting) && (empty($request->fa3_setting) || (!empty($request->fa3_setting) && count($request->fa3_setting) <= 0))){
            return response()->json(['status' => false, 'message' => 'Please select any one option']);
        } else {
            Notification::route('mail', Auth::user()->details->email)->notify(new OTPVerificationNotification());
            return response()->json(['status' => true, 'message' => 'OTP sent to your email', 'newRoute' => route('one-time-passcode.enableStore')]);
        }
    }

    public function OneTimePasscodeEnableStore(Request $request)
    {
        if (empty(Auth::user()->setting->fa3_setting) && (empty($request->fa3_setting) || (!empty($request->fa3_setting) && count($request->fa3_setting) <= 0))){
            return response()->json(['status' => false, 'message' => 'Please select any one option']);
        } else {
            $otp = $_COOKIE["otp"] ?? null;
            $requestOtp = is_array($request->otp) ? implode('',$request->otp) : $request->otp;
            if (!empty($otp) && Hash::check($requestOtp, $otp)) {
                $reqData['fa3_setting'] = $request->has('fa3_setting') ? implode(',', $request->fa3_setting) : null;
                UserSetting::where(['user_id' => Auth::id()])->update(['fa3_setting' => $reqData['fa3_setting']]);

                $fa3Setting = $request->fa3_setting ?? [];
                if (count(Auth::user()->setting->fa3_setting ?? []) >= count($fa3Setting) || in_array(null, $fa3Setting, true)) {
                    // disable
                    $diffArr = array_diff(Auth::user()->setting->fa3_setting, $fa3Setting);
                    foreach ($diffArr as $value) {
                        saveLog("User Disable One time passcode For " . $value, Auth::user(), [], "Disable one time passcode");
                    }
                }
                if ((count(Auth::user()->setting->fa3_setting ?? []) <= count($fa3Setting)) || !in_array(null, $fa3Setting, true)) {
                    // enable
                    $diffArr = array_diff($fa3Setting, Auth::user()->setting->fa3_setting);
                    foreach ($diffArr as $value) {
                        if ($value != null) {
                            saveLog("User Enable One time passcode For " . $value, Auth::user(), [], "Enable one time passcode");
                        }
                    }
                }
                Session::flash('flash_notification', 'One time passcode save successfully.');

                return response()->json(['status' => true, 'message' => "Successfully Verify your Code.",'reload_screen' => true]);
            } else {
                return response()->json(['status' => false, 'message' => "Invalid code. Please ensure you've entered the code correctly."]);
            }
        }
    }

    public function GetState(Request $request)
    {
        $options = "<option value='' selected>Select Region / State / Province</option>";
        $select_option = $request->selected_id;

        $query = State::query();
        if ($request->country_id){
            $query->where('country_id',$request->country_id);
        }
        $data = $query->orderby('name','ASC')->get();
        $count =$query->count();
        if (!empty($data)){
            foreach ($data as $row) {
                $selected = ($select_option == $row->id) ? 'selected' : '';
                $options .= "<option value='" . $row->id . "' $selected >" . $row->name . "</option>";
            }
        }

        return response()->json(['success' => true,'html' => $options,'count'=>$count]);
    }

    public function GetCity(Request $request)
    {
        $options = "<option value='' selected>Select City</option>";
        $select_option = $request->selected_id;

        $query = City::query();
        if ($request->state_id){
            $query->where('state_id',$request->state_id);
        }
        $data = $query->orderby('name','ASC')->get();

        if (!empty($data)){
            foreach ($data as $row) {
                $selected = ($select_option == $row->id) ? 'selected' : '';
                $options .= "<option value='" . $row->id . "' $selected >" . $row->name . "</option>";
            }
        }

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


    public function switchRole(Request $request)
    {
        $role = $request->role;
        $userRoles = Auth::user()->roles()->pluck('name')->toArray();
        if (in_array($role, $userRoles)) {
            Session::put('login_user_role', $role);
            $redirect = $this->redirectAfterLogin($role);
            return response()->json(['success' => true, 'url' => url($redirect)]);
        }
        return response()->json(['success' => false, 'msg' => "Please select valid role."], Response::HTTP_UNAUTHORIZED);
    }

    public static function redirectAfterLogin($role)
    {
        $redirect = '/member/dashboard';

        if (request()->ajax()) {
            return $redirect;
        }

        return redirect($redirect);
    }

    /**
     * @param Request $request
     * @param Export $export
     */
    public function exportDataPost(Request $request, Export $export)
    {
        $table = $request->table;
        $type = $request->type;
        $ids = explode(",", $request->id);
        $search = $request->filter;
        $defaultSearch = $request->defaultSearch;
        $filter = (array) json_decode($search);
        $user = Auth::user();
        $fieldsTable = $export->exportData($filter, $defaultSearch, $table, $user, $ids);

        $dashboard = [
            'activity_log_dashboard',
            'activity_log_sm_dashboard',
            'activity_log_cm_dashboard',
        ];

        $keys = explode(",", $request->keys);
        $page = $fieldsTable['page']->pageName ?? 'Logs';
        if ($table == 'news_sa' || $table == 'news_sa_archived') {
            $page = 'News';
        } else if ($table == 'press_sa' || $table == 'press_sa_archived') {
            $page = 'Press';
        } else if (
            $table == 'activity_log_my'
            || $table == 'activity_log_sm_my'
            || $table == 'activity_log_cm'
            || $table == 'activity_log_sa_my'
            || $table == 'activity_log_investor_my'
            || $table ==  'activity_log_translator_my'
            || $table == 'activity_my_log_member'
        ) {
            $page = 'My Logs';
        } else if ($table == 'csrlist') {
            $page = 'CSR list field settings';
        } else if ($table == 'orderlist') {
            $page = 'Order field settings';
        } else if ($table == 'sa_csr_holder_list') {
            $page = 'CSR Holders list';
        } else if ($table == 'member_withdraw_history') {
            $page = 'User Withdraw';
        } else if ($table == 'member_transfer_history') {
            $page = 'User Transfer';
        } else if ($table == 'member_all_history') {
            $page = 'User All';
        } else if ($table == 'sa_csr_retirement_setting') {
            $page = 'Review Logo & Url';
        } else if ($table == 'country_settings_sm') {
            $page = 'Countries';
        } else if ($table == 'wallet_sm') {
            $page = 'Wallet';
        } else if ($table == 'sa_wallet_history') {
            $page = 'Transaction History';
        } else if ($table == 'member_wallet_transaction') {
            $page = 'Transaction';
        }else if($table == 'member_earnings_transaction'){
            $page = 'Earnings Transaction';
        } else if ($table == 'my_redeemed_gift_codes') {
            $page = 'Redemptions';
        } else if ($table == 'my_gift_codes') {
            $page = 'My Gift Code';
        } else if ($table == 'invoices') {
            $page = 'Invoices';
        } else if ($table == 'referral_user_member') {
            $page = 'My Team';
        } else if ($table == 'redemption_req_list') {
            $page = 'Redemption Request List';
        }
        $columns = [];

        foreach ($keys as $check) {
            foreach ($fieldsTable['header'] as $key => $column) {
                if ($key == $check) {
                    $columns[$key] = $column;
                }
            }
        }
        $count = $fieldsTable['query']->count();
        if ($count > getSiteSettings('download_without_email_limit') && !in_array($table, $dashboard)) {
            $data = [
                'columns' => $columns,
                'keys' => $keys,
                'table' => $table,
                'user' => $user,
                'type' => $type,
                'ids' => $ids,
                'filter' => $filter,
                'defaultSearch' => $defaultSearch,
            ];
            $log = 'Exported ' . $type . ' file of ' . $page;
            saveLog($log, $user, [], "export");
            JobExport::dispatch($data);
            return response()->json([
                'success' => true,
            ]);
        } else if (
            getSiteSettings('download_without_email_limit') < 50
            && $count > getSiteSettings('download_without_email_limit')
        ) {
            $data = [
                'columns' => $columns,
                'keys' => $keys,
                'table' => $table,
                'user' => $user,
                'type' => $type,
                'ids' => $ids,
                'filter' => $filter,
                'defaultSearch' => $defaultSearch,
            ];
            $log = 'Exported ' . $type . ' file of ' . $page;
            saveLog($log, $user, [], "export");
            JobExport::dispatch($data);
            return response()->json([
                'success' => true,
            ]);
        }
        return response()->json([
            'data' => true,
        ]);
    }

    /**
     * @param Request $request
     * @param Export $export
     *
     * @return BinaryFileResponse|StreamedResponse
     */
    public function exportData(Request $request, Export $export)
    {
        $table = $request->table;
        $type = $request->type;
        $search = $request->filter;
        $filter = (array) json_decode($search);
        $date = Carbon::now()->format('Ymd');
        $ids = explode(",", $request->id);
        $user = Auth::user();
        $fieldsTable = $export->exportData($filter, false, $table, $user, $ids);
        $page = $fieldsTable['page']->pageName ?? 'Logs';
        if ($table == 'news_sa') {
            $page = 'News';
        } else if ($table == 'press_sa') {
            $page = 'Press';
        } else if (
            $table == 'activity_log_my'
            || $table == 'activity_log_sm_my'
            || $table == 'activity_log_cm'
            || $table == 'activity_log_sa_my'
            || $table == 'activity_log_investor_my'
            || $table == 'activity_log_translator_my'
            || $table == 'activity_my_log_member'
        ) {
            $page = 'My Logs';
        } else if ($table == 'csrlist') {
            $page = 'CSR list field settings';
        } else if ($table == 'orderlist') {
            $page = 'Order field settings';
        } else if ($table == 'sa_csr_holder_list') {
            $page = 'CSR Holders list';
        } else if ($table == 'member_withdraw_history') {
            $page = 'User Withdraw';
        } else if ($table == 'member_transfer_history') {
            $page = 'User Transfer';
        } else if ($table == 'member_all_history') {
            $page = 'User All';
        } else if ($table == 'sa_csr_retirement_setting') {
            $page = 'Review Logo & Url';
        } else if ($table == 'country_settings_sm') {
            $page = 'Countries';
        } else if ($table == 'wallet_sm') {
            $page = 'Wallet';
        } else if ($table == 'sa_wallet_history') {
            $page = 'Transaction History';
        } else if ($table == 'member_wallet_transaction') {
            $page = 'Transaction';
        } else if ($table == 'member_earnings_transaction') {
            $page = 'Earnings Transaction';
        } else if ($table == 'my_redeemed_gift_codes') {
            $page = 'Redemptions';
        } else if ($table == 'my_gift_codes') {
            $page = 'My Gift Code';
        } else if ($table == 'invoices') {
            $page = 'Invoices';
        } else if ($table == 'referral_user_member') {
            $page = 'My Team';
        } else if ($table == 'redemption_req_list') {
            $page = 'Redemption Request List';
        }
        $keys = explode(",", $request->keys);
        $appName = config('app.name');
        $fileName = $appName . '-' . $page . '-' . $date . '.csv';
        $headers = array(
            "Content-type" => "text/csv",
            "Content-Disposition" => "attachment; filename=$fileName",
            "Pragma" => "no-cache",
            "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
            "Expires" => "0",
        );
        $columns = [];
        foreach ($keys as $check) {
            foreach ($fieldsTable['header'] as $key => $col) {
                if ($key == $check) {
                    $columns[$key] = $col;
                }
            }
        }
        if ($table == "orderlist") {
            $investorShareLog = $fieldsTable['query']->all();
        } else {
            $investorShareLog = $fieldsTable['query']->get();
        }
        if ($type == 'zip') {
            $data = $export->zipfile($filter, false, $columns, $keys, $table, $user, $type, $ids);
            return response()->download($data['folder'] . '/' . $data['file']);
        } else {
            $callback = function () use ($investorShareLog, $columns, $fieldsTable, $keys, $table, $export) {
                $export->createfile($investorShareLog, $columns, $fieldsTable, $keys, $table);
            };
            $log = 'Exported ' . $type . ' file of ' . $page;
            saveLog($log, $user, [], "export");
            return response()->stream($callback, 200, $headers);
        }
    }

    /**
     * @param $folderName
     *
     *
     * @return array|Factory|View|BinaryFileResponse
     */
    public function downloadLink($folderName, $fileName)
    {
        $file = $folderName . $fileName;
        $headers = array(
            "Content-type" => "text/csv",
            "Content-Disposition" => "attachment; filename=$file",
            "Pragma" => "no-cache",
            "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
            "Expires" => "0",
        );
        if (!File::exists($file)) {
            return view('frontend.download-file');
        }
        return response()->download($file, 200, $headers);
    }

    public function updatePreference(Request $request)
    {
        $preference = $request->preference;
        $userSetting = UserSetting::firstOrCreate(['user_id' => Auth::id()]);
        $userSetting->preference = $preference;
        $userSetting->save();
        return response()->json(['success' => true, 'message' => 'Preferences updated successfully']);
    }

    public function updateUserCompany( Request $request)
    {
        if (readOnlyMode()) {
            return response()->json(['success' => false, 'message' => 'Feature disabled whilst in switched user mode.', 'data' => []]);
        }
        $validationRules = [
            'business_name' => ['required'],
            'vat_number' => ['nullable', 'alpha_num'],
            'company_registration_number' => ['nullable', 'business_name_ctm'],
            'company_owner_name' => ['nullable', 'business_name_ctm'],
            'company_director_name' => ['nullable', 'business_name_ctm'],
            'company_logo' => ['mimes:jpg,jpeg,png'],
        ];

        // Define custom error messages
        $customMessages = [
            'business_name.required' => 'The company name is required',
            'business_name.max' => 'The company name may not be greater than 255 characters.',
            'business_name.business_name_ctm' => 'The company name format is invalid.',
            'vat_number.alpha_num' => 'The VAT number may only contain letters and numbers.',
            'company_registration_number.business_name_ctm' => 'The company registration number format is invalid.',
            'company_owner_name.business_name_ctm' => 'The company owner name format is invalid.',
            'company_director_name.business_name_ctm' => 'The company director name format is invalid.',
        ];
        $validator = Validator::make($request->all(), $validationRules, $customMessages);

        if ($validator->fails()) {
            $errors = $validator->errors()->toArray();
            $formattedErrors = [];
            foreach ($errors as $field => $messages) {
                $formattedErrors[$field] = array_unique($messages);
            }
            $firstErrorMessage = collect($formattedErrors)->flatten()->first() ?? 'Validation failed.';
            $errorCount = collect($formattedErrors)->flatten()->count();
            $response = [
                'code' => 422,
                'errors' => $formattedErrors,
                'msg' => $firstErrorMessage
            ];

            if ($errorCount > 1) {
                $response['_message'] = "{$firstErrorMessage} (and " . ($errorCount - 1) . " more error" . ($errorCount > 2 ? 's' : '') . ")";
            }
            return response()->json($response, 422);
        }

        $message = 'Your Company Details has been updated successfully!';

        $requestData['business_name'] = $request->business_name;
        $requestData['company_registration_number'] = $request->company_registration_number;
        $requestData['vat_number'] = $request->vat_number;
        $requestData['company_owner_name'] = $request->company_owner_name;
        $requestData['company_director_name'] = $request->company_director_name;
        $requestData['company_url'] = $request->company_url;

        if ($request->hasFile('company_logo')) {
            $requestData['company_logo'] = uploadFileCsrAdmin($request->company_logo, '/upload/company-information/');
        }
        $oldCompanyData = Auth::user()->details->company;

        // Make API request
        $data = Http::withToken('Bearer ' . Session::get('api_login_token'))->withHeaders(getCsrNowApiHeader())->post(config('csrnow.api.live_endpoint') . 'auth/user-company', $requestData);
        $response = $data->object();

        if (isset($response->status) && $response->status ==  true) {
            // /*---- START for log ----*/
            if ($request->business_name != ($oldCompanyData->business_name ?? '')){
                saveLog('Your business name has been updated from ' . ($oldCompanyData->business_name ?? 'none') . ' to ' . $request->business_name, Auth::user(), Auth::user(), 'updated');
            }
            if ($request->company_registration_number != ($oldCompanyData->company_registration_number ?? '')){
                saveLog('Your company registeration number has been updated from ' . ($oldCompanyData->company_registration_number ?? 'none') . ' to ' . $request->company_registration_number, Auth::user(), Auth::user(), 'updated');
            }
            if ($request->vat_number != ($oldCompanyData->vat_number ?? '')){
                saveLog('Your vat number has been updated from ' . ($oldCompanyData->vat_number ?? 'none') . ' to ' . $request->vat_number, Auth::user(), Auth::user(), 'updated');
            }
            if ($request->company_owner_name != ($oldCompanyData->company_owner_name ?? '')){
                saveLog('Your company owner name has been updated from ' . ($oldCompanyData->company_owner_name ?? 'none') . ' to ' . $request->company_owner_name, Auth::user(), Auth::user(), 'updated');
            }
            if ($request->company_director_name != ($oldCompanyData->company_director_name ?? '')){
                saveLog('Your company director name has been updated from ' . ($oldCompanyData->company_director_name ?? 'none') . ' to ' . $request->company_director_name, Auth::user(), Auth::user(), 'updated');
            }
            if ($request->company_url != ($oldCompanyData->company_url ?? '')){
                saveLog('Your company URL has been updated from ' . ($oldCompanyData->company_url ?? 'none') . ' to ' . $request->company_url, Auth::user(), Auth::user(), 'updated');
            }
            if ($oldCompanyData) {
                // Check if the company logo has changed and log the update
                if ((isset($request->company_logo) && $request->company_logo !== $oldCompanyData->company_logo) && $request->hasFile('company_logo')) {

                    saveLog(
                        'Your company logo has been updated from ' . ($oldCompanyData->company_logo ?? 'none') . ' to ' .$requestData['company_logo'],
                        Auth::user(),
                        Auth::user(),
                        'updated'
                    );
                }
            }
            // /*---- END for log ----*/

            $status = false;
            if(!empty($oldCompanyData)){
                if ((isset($request->company_logo) && $request->company_logo != $oldCompanyData->company_logo) ||isset($request->company_url) && $oldCompanyData->company_url != $request->company_url) {
                    $status = true;
                }
            }

            return response()->json(['success' => true, 'message' => $message, 'data' => $response, 'record' => 'updated','status' => $status]);
        } else {
            $msg = (isset($response->message)) ? ((is_string($response->message)) ? $response->message : array_values((array) $response->message)[0][0]) : 'Getting some error.';
            return response()->json(['status' => "No", 'msg' => $msg], $data->getStatusCode());
        }
    }

}
