<?php

namespace App\Http\Controllers\Grade;

use App\ApprovalRule;
use App\ApprovalRuleLog;
use App\ApprovalStatusLog;
use App\AutoReject;
use App\AutoRejectRule;
use App\AutoRejectLogs;
use App\ConsumerApplication;
use App\ConsumerApplicationFiles;
use App\CreditReport;
use App\EPFUANLookup;
use App\GradeLock;
use App\Grades;
use App\GradesV1;
use App\GSTPANData;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Controller;
use App\Imports\TestImport;
use App\MerchantOffers;
use App\PreApproval;
use App\PreApprovalLog;
use App\Products;
use App\PWAApplicationForm;
use App\Slack;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use App\Http\Controllers\Grade\GradeController;
use App\EpfFailureLog;
use Illuminate\Support\Facades\Storage;
use App\Logging\CloudWatchLoggerFactory;
use App\BreLog;
use App\JsonBreApprovalStatusLog;
use App\JWTAccess;
use Hashids\Hashids;
use App\Http\Controllers\JsonBREController;
use App\StatusLogs;
use App\Http\Controllers\ApiController;
use Illuminate\Support\Facades\Input;
use App\Http\Controllers\Service\ServiceController;

class AutoRejection extends Controller
{
    private $dpdCountRejection = 0;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function autoReject($grade, $id, $source = 'bot', $tracking_id='', $account_aggregator_id='')
    {
        try {
            if (_env('JSON_BRE_ACTIVE')) {
                return $this->autoRejectJSONBRE($grade, $id, $source, $tracking_id, $account_aggregator_id);
            }
            $cwFactory = new CloudWatchLoggerFactory();
            $this->rejectRules = [];
            $failLogs = [];
            $check_approval = [];
            $credit = CreditReport::where('application_id', $id)->first(['Score', 'TotalPastDue']);
            $application = ConsumerApplication::find($id);

            $statusLogs = StatusLogs::where('application_id',$id)->where('status', 'rejected')->where('user_id', 107)->first(['id']);
            $cwFactory->logger(json_encode(['title' => 'Status Log Check', 'application_id' => $id, 'statusLogs' => isset($statusLogs->id) ? 'true' : 'false']));
            if (isset($statusLogs->id)){
                return false;
            }

            if((new ConsumerApplicationController())->isExistingCustomer($id)) {
                $cwFactory->logger(json_encode(['title' => 'Existing Customer failed', 'application_id' => $id]));
                return false;
            }

            $Score = -2;
            $TotalPastDue = 0;
            if (isset($credit->Score)) {
                $Score = $credit->Score;
                $TotalPastDue = $credit->TotalPastDue;
            }

            if(!isset($credit->Score)){
                $Score = -2;
            }

            $age = (date('Y', strtotime($application->created_at)) - date('Y', strtotime($application->dob)));
            $age = $age ? $age : $this->age;
            $application = ConsumerApplication::with(['merchant', 'merchant.autoRejectConsumer', 'merchant.autoReject', 'merchant.autoRejectRule', 'application_element' => function ($query) {
                $query->select('application_id', 'installation_address_pincode');
            }, 'foir'])
                ->where('id', $id)
                ->first(['id', 'name', 'email', 'mobile_number', 'lender_id', 'loan_amount', 'merchant_id', 'monthly_income', 'current_address_pincode', 'permanent_address_pincode', 'co_applicant_address_pincode']);
            $autoReject = true;

            $noDPDDateRange = Carbon::now()->subYear(2)->startOfDay()->toDateTimeString();
            $dpdCountRejection = $this->dpdCountRejection;
            if(!$this->dpdCountRejection && count($application->foir)){
                foreach ($application->foir as $foir) {

                    $foirData = json_decode($foir->dpd, 1);
                    if (strtotime($foir->DateOpened) <= strtotime($noDPDDateRange)) {
                        $dpdCount = 0;
                        foreach ($foirData as $key => $item) {
                            if (!in_array($key, ['NEW', '*', '000', 'CLSD'])) {
                                $dpdCount += $item;
                                if ($dpdCount > 6) {
                                    $dpdCountRejection = $dpdCount;
                                }
                            }
                        }
                    }
                }
            }

            (new GradeController(new Request()))->getFOIRByID($application->id);

            if ((!isset($credit->Score) || !$application->monthly_income || !$age) && $source != 'consumer') {
                $cwFactory->logger(json_encode(['title' => 'Basic Check', 'application_id' => $id]));
                return false;
            }
            if($application->merchant && !$application->merchant->grade_v1){
                if (($Score > 10 && $Score < 580 && (($TotalPastDue > 5000) || $dpdCountRejection)) || ($age > 65)) {
                    $applicationController = new ConsumerApplicationController();
                    $applicationController->applicationRejectMail($application, $autoReject);
                    $applicationController->sendMessageToMerchant('rejected', $application->id);
                    if($Score > 10 && $Score < 580) {
                        $this->rejectRules[] = 'score';
                    }if($TotalPastDue > 5000){
                        $this->rejectRules[] = 'past dues';
                    }if($dpdCountRejection){
                        $this->rejectRules[] = 'dpd';
                    }if($age > 65){
                        $this->rejectRules[] = 'age';
                    }
                    $this->autoRejectLog($id);
                    return true;
                }
            }

            $dataLists = (new ConsumerApplicationController())->getUnapprovedPincodes($id);
            $pincode_approval = false;
            if ($dataLists['unapproved_pin_codes'] && (!isset($dataLists['approver_data_exist']->id))) {
                $pincode_approval = true;
            }

            if (((isset($application->current_address_pincode)) && !empty($application->current_address_pincode)) || ((isset($application->application_element->installation_address_pincode)) && !empty($application->application_element->installation_address_pincode))) {
                $data['current_pincode'] = ((isset($application->current_address_pincode)) && !empty($application->current_address_pincode)) ? $application->current_address_pincode : "";
                $data['installation_pincode'] = ((isset($application->application_element->installation_address_pincode)) && !empty($application->application_element->installation_address_pincode)) ? $application->application_element->installation_address_pincode : "";
                $consumerApplicationConreoller = new ConsumerApplicationController();
                $NegativeArearesponse = $consumerApplicationConreoller->getNegativeAreaList($data);
                if ($NegativeArearesponse && isset($NegativeArearesponse->level) && $NegativeArearesponse->level == 1) {
                    $check_approval['negative_area'] = true;
                }
            }

            if($source == 'consumer'){
                try {
                    $autoRejectRule = $application->merchant && $application->merchant->autoRejectConsumer ? $application->merchant->autoRejectConsumer : '';
                    if (!$autoRejectRule->negative_area) {
                        $check_approval['negative_area'] = false;
                    }
                    if(isset($autoRejectRule->id)) {
                        $foirData = FOIR::where('application_id', $id)->whereNotIn('AccountType', ['Gold Loan', 'Overdraft', 'Loan against Shares/Securities'])->first(['id']);
                        if (!$autoRejectRule->approved_pincode) {
                            $pincode_approval = false;
                        }
                        if ((($Score >= $autoRejectRule->min_score && $Score <= $autoRejectRule->max_score) || $TotalPastDue >= $autoRejectRule->past_dues) || ($dpdCountRejection >= $autoRejectRule->max_dpd) || $age >= $autoRejectRule->age || $application->monthly_income <= $autoRejectRule->monthly_income ||
                            (!isset($foirData->id) && $Score != -2) || ($this->cfFoir >= $autoRejectRule->foir) || $check_approval['negative_area'] || $pincode_approval) {
                            $this->sendAutoRejectCommunication($application, $autoReject);
                            if($Score >= $autoRejectRule->min_score && $Score <= $autoRejectRule->max_score) {
                                $this->rejectRules[] = 'score';
                            }if($TotalPastDue >= $autoRejectRule->past_dues){
                                $this->rejectRules[] = 'past dues';
                            }if($dpdCountRejection >= $autoRejectRule->max_dpd){
                                $this->rejectRules[] = 'dpd';
                            }if($age >= $autoRejectRule->age){
                                $this->rejectRules[] = 'age';
                            }if($application->monthly_income <= $autoRejectRule->monthly_income){
                                $this->rejectRules[] = 'income';
                            }if((!isset($foirData->id) && $Score != -2)){
                                $this->rejectRules[] = 'score';
                            }if($this->cfFoir >= $autoRejectRule->foir){
                                $this->rejectRules[] = 'foir';
                            }if($check_approval['negative_area']){
                                $this->rejectRules[] = 'negative area';
                            }if($pincode_approval){
                                $this->rejectRules[] = 'pincode approval';
                            }
                            $this->autoRejectLog($id);
                            return true;
                        }
                    }
                }catch (\Exception $e){
                }
                return false;
            }

            $autoRejectRule = $application->merchant && $application->merchant->autoRejectRule ? $application->merchant->autoRejectRule : '';
            $cwFactory->logger(json_encode(['title' => 'Reject Rule Check', 'application_id' => $id, 'autoRejectRule' => isset($autoRejectRule) ? 'true' : 'false']));
            if($autoRejectRule && isset($autoRejectRule)){
                try{
                    $hashids = new Hashids('Creditfair by CS', 20);
                    $hashed_application_id = $hashids->encode($application->id);
                    $url = 'http://127.0.0.1:5050/api/run-auto-reject/'.$hashed_application_id;
                    // $token = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTc0NTgzNzU2OCwiZXhwIjoxNzQ4MzQzMDQyfQ.WUcDLs-Gw5hNb9p4mdqZVJaLxV9A3W7srwvKRJLmLypp2wQF1x1B-vN6LrSB-HPRfN2Y93g1lUgRpAlapyHBYQ';
                    
                    $jwt = new JWTAccess();
                    $request = new Request();
                    $request->merge(['application_id'=> $hashed_application_id]);
                    $token = $jwt->encodeJWTDecisionEngine($request, _env("JWT_KEY_512"));

                    if ($source != 'banking') {
                        $ch = curl_init();
                        curl_setopt($ch, CURLOPT_URL, $url);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                        curl_setopt($ch, CURLOPT_HTTPHEADER, [
                            "Authorization: Bearer $token"
                        ]);

                        $response = curl_exec($ch);
                        // $response = '{"status":"success","auto_reject_status":false,"rejection_logs":[{"MAX_AGE":{"result":true}},{"MIN_AGE":{"result":true}},{"NACH_BOUNCE":{"result":true}},{"NEGATIVE_AREA":{"result":true}},{"ACCOUNT_STATUS":{"result":true}},{"MONTHLY_INCOME":{"result":true}},{"TOTAL_PAST_DUES":{"result":true}},{"APPROVED_PINCODE":{"result":true}},{"PRINCIPAL_WRITTEN_OFF_AMOUNT":{"result":true}},{"DPD_KEYWORD":{"result":false,"details":[{"rule":{"value":"30","operator":">=","tradelines":"1","name":"dpd","months":6},"records":["XXXXXXXXXX3336 - {\"Year\": \"2025\", \"Month\": \"03\", \"Days_Past_Due\": \"33\", \"Asset_Classification\": \"?\"}"]},{"rule":{"value":"60","operator":">=","tradelines":"1","name":"dpd","months":12},"records":["XXXXXXXXXX3336 - {\"Year\": \"2025\", \"Month\": \"04\", \"Days_Past_Due\": \"62\", \"Asset_Classification\": \"?\"}"]},{"rule":{"value":"M","operator":">=","tradelines":"1","name":"keyword","months":24},"records":["XXXXXXXXXX3336 - {\"Year\": \"2024\", \"Month\": \"10\", \"Days_Past_Due\": null, \"Asset_Classification\": \"M\"}","XXXXXXXXXX9594 - {\"Year\": \"2025\", \"Month\": \"04\", \"Days_Past_Due\": null, \"Asset_Classification\": \"M\"}","XXXXXXXXXX9180 - {\"Year\": \"2025\", \"Month\": \"03\", \"Days_Past_Due\": null, \"Asset_Classification\": \"M\"}"]}]}},{"MIN_MAX_SCORE":{"result":true}}]}';
                        $rejectionData = json_decode($response, 1);
                        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                        $err = curl_error($ch);
                        curl_close($ch);

                        $cwFactory->logger(json_encode(['err' => $err, 'httpcode' => $httpcode,'token' => $token, 'url' => $url, 'key' => _env("JWT_KEY_512"), 'response' => $response, 'application_id' => $id, 'title'=> 'Auto-reject-API']));
                        if (isset($rejectionData['status']) && $rejectionData['status'] == 'success' && isset($rejectionData['auto_reject_status']) && !$rejectionData['auto_reject_status']) {
                            $rejectionLogs = $rejectionData['rejection_logs'];
                            foreach($rejectionLogs as $index => $arrayData){
                                foreach ($arrayData as $key => $result) {
                                    if (isset($result['result']) && $result['result'] == false) {
                                        $this->rejectRules[] = $key;
                                        if ($key == 'DPD_KEYWORD'){
                                            if (isset($result['details'])) {
                                                foreach($result['details'] as $item) {
                                                    $ruleName = strtoupper($item['rule']['name']);
                                                    if (!isset($failLogs[$ruleName])) {
                                                        $failLogs[$ruleName]['rules'] = [];
                                                    }
                                                    $failLogs[$ruleName]['rules'][] = $item['rule'];
                                                    $failLogs[$ruleName]['records'][] = $item['records'];
                                                }
                                            }
                                        } else {
                                            $failLogs[$key] = ['rules' => isset($result['details']) ? (array_column($result['details'], 'rule') != null ? array_column($result['details'], 'rule') : $result['details']['rule']) : null];
                                        }
                                    }
                                }
                            }
                        }
                    }
                    # Check if bank analysis exists
                    $fileType = DB::select("select file_type from consumer_application_files where consumer_application_id = ".$id." and file_type = 'pirimid_analysis_excel'");
                    if (isset($fileType[0]) && $fileType[0]->file_type == 'pirimid_analysis_excel') {
                        $bankLogs = $this->runBankRejection($hashed_application_id, $token);
                        $failLogs = array_merge($failLogs, $bankLogs);
                    }
                    if ($this->rejectRules != []) {
                        $this->sendAutoRejectCommunication($application, $autoReject);
                        $this->autoRejectLog($id, json_encode($failLogs));
                        return true;
                    }
                } catch (\Exception $e){
                    $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
                }
            }
            return false;
        } catch (\Exception $e) {
            $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
            return false;
        }
    }

    public function autoRejectJSONBRE($grade, $id, $source = 'bot', $tracking_id='', $account_aggregator_id='')
    {
        try {
            $cwFactory = new CloudWatchLoggerFactory();
            $this->rejectRules = [];
            $failLogs = [];
            $check_approval = [];
            $credit = CreditReport::where('application_id', $id)->first(['Score', 'TotalPastDue']);
            $application = ConsumerApplication::find($id);

            $statusLogs = StatusLogs::where('application_id',$id)->where('status', 'rejected')->where('user_id', 107)->first(['id']);
            $cwFactory->logger(json_encode(['title' => 'Status Log Check', 'application_id' => $id, 'statusLogs' => isset($statusLogs->id) ? 'true' : 'false']));
            if (isset($statusLogs->id)){
                return false;
            }

            // if((new ConsumerApplicationController())->isExistingCustomer($id)) {
            //     $cwFactory->logger(json_encode(['title' => 'Existing Customer failed', 'application_id' => $id]));
            //     return false;
            // }

            $Score = -2;
            $TotalPastDue = 0;
            if (isset($credit->Score)) {
                $Score = $credit->Score;
                $TotalPastDue = $credit->TotalPastDue;
            }

            if(!isset($credit->Score)){
                $Score = -2;
            }

            $age = (date('Y', strtotime($application->created_at)) - date('Y', strtotime($application->dob)));
            $age = $age ? $age : $this->age;
            $application = ConsumerApplication::with(['merchant', 'merchant.autoRejectConsumer', 'merchant.autoReject', 'merchant.autoRejectRule', 'application_element' => function ($query) {
                $query->select('application_id', 'installation_address_pincode');
            }, 'foir'])
                ->where('id', $id)
                ->first(['id', 'name', 'email', 'mobile_number', 'lender_id', 'loan_amount', 'merchant_id', 'monthly_income', 'current_address_pincode', 'permanent_address_pincode', 'co_applicant_address_pincode']);
            $autoReject = true;

            $noDPDDateRange = Carbon::now()->subYear(2)->startOfDay()->toDateTimeString();
            $dpdCountRejection = $this->dpdCountRejection;
            if(!$this->dpdCountRejection && count($application->foir)){
                foreach ($application->foir as $foir) {

                    $foirData = json_decode($foir->dpd, 1);
                    if (strtotime($foir->DateOpened) <= strtotime($noDPDDateRange)) {
                        $dpdCount = 0;
                        foreach ($foirData as $key => $item) {
                            if (!in_array($key, ['NEW', '*', '000', 'CLSD'])) {
                                $dpdCount += $item;
                                if ($dpdCount > 6) {
                                    $dpdCountRejection = $dpdCount;
                                }
                            }
                        }
                    }
                }
            }
            (new GradeController(new Request()))->getFOIRByID($application->id);
            if ((!isset($credit->Score) || !$application->monthly_income || !$age) && $source != 'consumer') {
                $cwFactory->logger(json_encode(['title' => 'Basic Check', 'application_id' => $id]));
                return false;
            }
            if($application->merchant && !$application->merchant->grade_v1){
                if (($Score > 10 && $Score < 580 && (($TotalPastDue > 5000) || $dpdCountRejection)) || ($age > 65)) {
                    $applicationController = new ConsumerApplicationController();
                    $applicationController->applicationRejectMail($application, $autoReject);
                    $applicationController->sendMessageToMerchant('rejected', $application->id);
                    if($Score > 10 && $Score < 580) {
                        $this->rejectRules[] = 'score';
                    }if($TotalPastDue > 5000){
                        $this->rejectRules[] = 'past dues';
                    }if($dpdCountRejection){
                        $this->rejectRules[] = 'dpd';
                    }if($age > 65){
                        $this->rejectRules[] = 'age';
                    }
                    $this->autoRejectLog($id);
                    return true;
                }
            }
            $dataLists = (new ConsumerApplicationController())->getUnapprovedPincodes($id);
            $pincode_approval = false;
            if ($dataLists['unapproved_pin_codes'] && (!isset($dataLists['approver_data_exist']->id))) {
                $pincode_approval = true;
            }

            if (((isset($application->current_address_pincode)) && !empty($application->current_address_pincode)) || ((isset($application->application_element->installation_address_pincode)) && !empty($application->application_element->installation_address_pincode))) {
                $data['current_pincode'] = ((isset($application->current_address_pincode)) && !empty($application->current_address_pincode)) ? $application->current_address_pincode : "";
                $data['installation_pincode'] = ((isset($application->application_element->installation_address_pincode)) && !empty($application->application_element->installation_address_pincode)) ? $application->application_element->installation_address_pincode : "";
                $consumerApplicationConreoller = new ConsumerApplicationController();
                $NegativeArearesponse = $consumerApplicationConreoller->getNegativeAreaList($data);
                if ($NegativeArearesponse && isset($NegativeArearesponse->level) && $NegativeArearesponse->level == 1) {
                    $check_approval['negative_area'] = true;
                }
            }
            if($source == 'consumer'){
                try {
                    $autoRejectRule = $application->merchant && $application->merchant->autoRejectConsumer ? $application->merchant->autoRejectConsumer : '';
                    if (!$autoRejectRule->negative_area) {
                        $check_approval['negative_area'] = false;
                    }
                    if(isset($autoRejectRule->id)) {
                        $foirData = FOIR::where('application_id', $id)->whereNotIn('AccountType', ['Gold Loan', 'Overdraft', 'Loan against Shares/Securities'])->first(['id']);
                        if (!$autoRejectRule->approved_pincode) {
                            $pincode_approval = false;
                        }
                        if ((($Score >= $autoRejectRule->min_score && $Score <= $autoRejectRule->max_score) || $TotalPastDue >= $autoRejectRule->past_dues) || ($dpdCountRejection >= $autoRejectRule->max_dpd) || $age >= $autoRejectRule->age || $application->monthly_income <= $autoRejectRule->monthly_income ||
                            (!isset($foirData->id) && $Score != -2) || ($this->cfFoir >= $autoRejectRule->foir) || $check_approval['negative_area'] || $pincode_approval) {
                            $this->sendAutoRejectCommunication($application, $autoReject);
                            if($Score >= $autoRejectRule->min_score && $Score <= $autoRejectRule->max_score) {
                                $this->rejectRules[] = 'score';
                            }if($TotalPastDue >= $autoRejectRule->past_dues){
                                $this->rejectRules[] = 'past dues';
                            }if($dpdCountRejection >= $autoRejectRule->max_dpd){
                                $this->rejectRules[] = 'dpd';
                            }if($age >= $autoRejectRule->age){
                                $this->rejectRules[] = 'age';
                            }if($application->monthly_income <= $autoRejectRule->monthly_income){
                                $this->rejectRules[] = 'income';
                            }if((!isset($foirData->id) && $Score != -2)){
                                $this->rejectRules[] = 'score';
                            }if($this->cfFoir >= $autoRejectRule->foir){
                                $this->rejectRules[] = 'foir';
                            }if($check_approval['negative_area']){
                                $this->rejectRules[] = 'negative area';
                            }if($pincode_approval){
                                $this->rejectRules[] = 'pincode approval';
                            }
                            $this->autoRejectLog($id);
                            return true;
                        }
                    }
                }catch (\Exception $e){
                }
                return false;
            }
            $autoRejectRule = DB::selectOne("SELECT modifications from auto_reject_rule where grade_id = ? and applicant_type = 1 order by created_at desc", [$application->merchant->grade_id]);
            $cwFactory->logger(json_encode(['title' => 'Reject Rule Check', 'application_id' => $id, 'autoRejectRule' => isset($autoRejectRule) ? 'true' : 'false']));
            if(isset($autoRejectRule->modifications)){
                try{
                    $testImport = new TestImport(new Request());
                    $requestID = $testImport->random_strings(8);
                    $req_id = $requestID;
                    $response = (new JSONBREController())->runRejection($id, $req_id, $autoRejectRule, false, $tracking_id, 1, $account_aggregator_id);
                    if (!$response instanceof JsonResponse){
                        return false;
                    }
                    $response = $response->getData(true);
                    $cwFactory->logger(json_encode(['response' => $response['res'], 'application_id' => $id, 'title'=> 'Auto-reject-API']));
                    $rejectionData = json_decode($response['res'], 1);
                    // $rejectionData = json_decode('{"policy-rejection":{"failed_condition":{"key":"nach_bounce","reason":"Value not found in s3"},"policy_status":false,"rules":[{"against":[0,"equal"],"key":"dpd_rejection_rules","log":[],"reason":"Passed: 0 equal 0","result":true,"source":0},{"against":[0,"equal"],"key":"keyword_experian_rejection","log":[],"reason":"Passed: 0 equal 0","result":true,"source":0},{"against":[45,"inBetween"],"key":"age_range","log":[],"reason":"Passed: 45 in between 20 and 64","result":true,"source":[20,64]},{"against":["744","notInBetween"],"key":"credit_score_range","log":[],"reason":"Passed: 744 not in between 300 and 624","result":true,"source":[300,624]},{"against":[],"key":"nach_bounce","log":["Execution halted: Value not found in s3"],"reason":"Value not found in s3","result":false,"source":[]},{"against":[1,"equal"],"key":"negative_area","log":[],"reason":"Passed: 1 equal 1","result":true,"source":1},{"against":[0,"equal"],"key":"account_status_rejection_rules","log":[],"reason":"Passed: 0 equal 0","result":true,"source":0},{"against":[200000,"greaterThanEqual"],"key":"monthly_income","log":[],"reason":"Passed: 200000.0 greaterThanEqual 19999","result":true,"source":19999},{"against":[0,"equal"],"key":"total_past_dues","log":[],"reason":"Passed: 0 equal 0","result":true,"source":0},{"against":[0,"equal"],"key":"principal_write_off_amount","log":[],"reason":"Passed: 0 equal 0","result":true,"source":0}]},"status":false}',1);
                    if (isset($rejectionData['status']) && !$rejectionData['status']) {
                        $rejectionRules = $rejectionData['policy-rejection']['rules'];
                        foreach($rejectionRules as $rule){
                            if (isset($rule['result']) && $rule['result'] == false && (isset($rule['reason']) && $rule['reason'] != 'Value not found in s3')) {
                                $formattedValue = $this->formatRejectionLogs($rule);
                                $this->rejectRules[] = in_array($formattedValue['key'], ['DPD', 'KEYWORD']) ? 'DPD_KEYWORD' : $formattedValue['key'];
                                $failLogs[$formattedValue['key']] = $formattedValue['log'];
                            }
                        }
                    }
                    if ($this->rejectRules != []) {
                        $this->sendAutoRejectCommunication($application, $autoReject);
                        $this->autoRejectLog($id, json_encode($failLogs));
                        return true;
                    }
                } catch (\Exception $e){
                    $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
                }
            }
            return false;
        } catch (\Exception $e) {
            $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
            return false;
        }
    }

    public function autoRejectCoApplicantJSONBRE($grade, $id, $tracking_id='')
    {
        try {
            $cwFactory = new CloudWatchLoggerFactory();
            $this->rejectRules = [];
            $failLogs = [];
            
            $application = ConsumerApplication::find($id);
            if (!$application) {
                return false;
            }

            // Fetch Co-applicant rules (applicant_type = 2)
            $autoRejectRule = DB::selectOne("SELECT modifications from auto_reject_rule where grade_id = ? and applicant_type = 2 order by created_at desc", [$application->merchant->grade_id]);
            
            if (isset($autoRejectRule->modifications)) {
                try {
                    $testImport = new TestImport(new Request());
                    $req_id = $testImport->random_strings(8);
                    
                    // Unified BRE call for both Co-applicant roles
                    $response = (new JSONBREController())->runRejection($id, $req_id, $autoRejectRule, false, $tracking_id, 2);
                    
                    if (!$response instanceof JsonResponse) {
                        return false;
                    }
                    
                    $responseData = $response->getData(true);
                    $rejectionData = json_decode($responseData['res'], true);
                    
                    // The co-applicant check might have multiple policies (income, signing)
                    // We group results by role (Income vs Signing)
                    foreach ($rejectionData as $policyKey => $policyData) {
                        if (strpos($policyKey, 'policy-rejection') === 0 && isset($policyData['policy_status']) && !$policyData['policy_status']) {
                            $roleKey = str_replace('policy-rejection-', '', $policyKey);
                            if ($roleKey == 'policy-rejection') $roleKey = 'general';
                            
                            if (!isset($failLogs[$roleKey])) {
                                $failLogs[$roleKey] = [];
                            }

                            $rejectionRules = $policyData['rules'];
                            foreach ($rejectionRules as $rule) {
                                if (isset($rule['result']) && $rule['result'] == false && (isset($rule['reason']) && $rule['reason'] != 'Value not found in s3')) {
                                    $formattedValue = $this->formatRejectionLogs($rule);
                                    $ruleKey = in_array($formattedValue['key'], ['DPD', 'KEYWORD']) ? 'DPD_KEYWORD' : $formattedValue['key'];
                                    
                                    if (!in_array($ruleKey, $this->rejectRules)) {
                                        $this->rejectRules[] = $ruleKey;
                                    }
                                    
                                    if (!isset($failLogs[$roleKey][$formattedValue['key']])) {
                                        $failLogs[$roleKey][$formattedValue['key']] = $formattedValue['log'];
                                    } else {
                                        if (isset($formattedValue['log']['rules'])) {
                                            $failLogs[$roleKey][$formattedValue['key']]['rules'] = array_merge($failLogs[$roleKey][$formattedValue['key']]['rules'] ?? [], (array)$formattedValue['log']['rules']);
                                        }
                                        if (isset($formattedValue['log']['records'])) {
                                            $failLogs[$roleKey][$formattedValue['key']]['records'] = array_merge($failLogs[$roleKey][$formattedValue['key']]['records'] ?? [], (array)$formattedValue['log']['records']);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    
                    if ($this->rejectRules != []) {
                        $this->autoRejectLog($id, json_encode($failLogs), 2);
                        return true;
                    }
                } catch (\Exception $e) {
                    $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
                }
            }
            return false;
        } catch (\Exception $e) {
            $cwFactory->logger(json_encode(['application_id' => $id, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
            return false;
        }
    }

    public function autoRejectLog($id, $logs = null, $applicant_type = 1)
    {
        if ($this->rejectRules) {
            $requestID = $this->request->has('request_ap_id') ? $this->request->get('request_ap_id') : '';
            AutoRejectLogs::insert([
                'application_id' => $id,
                'applicant_type' => $applicant_type,
                'reason' => implode(', ', $this->rejectRules),
                'created_at' => Carbon::now()->toDateTimeString(),
                'request_id' => $requestID,
                'failure_details' => $logs
            ]);

            $commentContent = ($applicant_type == 2 ? 'Co-applicant' : 'Applicant') . ' Auto Rejection Results - ';
            $additionalFields = ['reason' => $this->rejectRules, 'applicant_type' => $applicant_type];

            if ($applicant_type == 2 && $logs) {
                $decodedLogs = json_decode($logs, true);
                if (is_array($decodedLogs)) {
                    $signingKeys = isset($decodedLogs['signing']) ? array_keys($decodedLogs['signing']) : [];
                    $incomeKeys = isset($decodedLogs['income']) ? array_keys($decodedLogs['income']) : [];

                    if (!empty($signingKeys)) {
                        $commentContent .= ' | Signing: ' . implode(', ', $signingKeys);
                        $additionalFields['signing'] = $signingKeys;
                    }
                    if (!empty($incomeKeys)) {
                        $commentContent .= ' | Income: ' . implode(', ', $incomeKeys);
                        $additionalFields['income'] = $incomeKeys;
                    }
                }

                $application = ConsumerApplication::where('id', $id)->first(['merchant_id', 'created_by']);
                $createdBy = $application->created_by ?? 0;
                // Tagging the updated_by user as @user_id- as per ApiController logic
                $commentWithTag = $commentContent . ' @' . $createdBy . '-';

                (new ApiController())->updateComments(Input::merge([
                    'application_id' => $id,
                    'id' => 107,
                    'comment' => $commentWithTag,
                    'show_merchant' => 0,
                    'show_consumer' => 0,
                    'confidential_notes' => 0
                ]));
            }

            if (isset($application->merchant_id) && $application->merchant_id > 0) {
                $status = 'rejected';
                $applicationController = new ConsumerApplicationController();
                $applicationController->webhook($id, [
                    'merchant_id' => $application->merchant_id,
                    'type' => 'Application-Webhook',
                    'status' => $status,
                    'data' => $applicationController->getMConnectPayload($id, $status, $additionalFields)
                ]);
                if (_env('WHATSAPP_STATUS_AND_COMMENT')){
                    try {
                        if ($applicant_type == 1) {
                            (new ServiceController(new Request()))->sendGroupStatusNotification($id, $status);
                        }
                    } catch (\Exception $e) {
                        (new Slack(new Request(['title' => 'Whatsapp notification sending on status change failed', 'fields' => ['e' => $e->getMessage(),'l' => $e->getLine(),'t' => $e->getTraceAsString(), 'id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
                    }
                }
            }
        }
    }

    public function sendAutoRejectCommunication($application, $autoReject){
        $applicationController = new ConsumerApplicationController();
        $applicationController->applicationRejectMail($application, $autoReject);
        $applicationController->sendMessageToMerchant('rejected', $application->id);
    }

    public function runBankRejection($hashed_application_id, $token) {
        $url = "http://127.0.0.1:5050/api/run-auto-reject-bank/".$hashed_application_id;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer $token"
        ]);
        // $bankResponse = '{"status":"success","auto_reject_bank_status":false,"rejection_logs":{"NACH_BOUNCE":{"result":false,"details":{"rule":[{"rule":{"value":"1","months":"12","operator":">"},"bank_transactions":[{"month":"2024-09-01T00:00:00","totalEmiBounceTxn":1,"totalEmiBounceAmt":1000},{"month":"2025-02-01T00:00:00","totalEmiBounceTxn":1,"totalEmiBounceAmt":2000}]}]}}}}';
        $bankResponse = curl_exec($ch);
        $bankData = json_decode($bankResponse, 1);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);
        if (isset($bankData['status']) && $bankData['status'] == 'success' && isset($bankData['auto_reject_bank_status']) && !$bankData['auto_reject_bank_status']) {
            $bankRejectionLogs = $bankData['rejection_logs'];
            foreach($bankRejectionLogs as $bankKey => $value) {
                if (isset($value['result']) && $value['result'] == false) {
                    $this->rejectRules[] = $bankKey;
                    $logs[$bankKey]['rules'] = array_column($value['details'], 'rule');
                }
            }
        }
        return isset($logs) ? $logs : [];
    }

    public function formatRejectionLogs($details) {
        $rejectionKeyDict = [
            'credit_score_range' => 'MIN_MAX_SCORE',
            'rejection_total_past_dues_equifax' => 'TOTAL_PAST_DUES',
            'total_past_dues' => 'TOTAL_PAST_DUES',
            'rejection_dpd_equifax' => 'DPD',
            'dpd_rejection_rules' => 'DPD',
            'rejection_keyword_equifax'=> 'KEYWORD',
            'keyword_experian_rejection' => 'KEYWORD',
            'rejection_account_status_equifax'=> 'ACCOUNT_STATUS',
            'account_status_rejection_rules' => 'ACCOUNT_STATUS',
            'rejection_principal_written_off_amount_equifax' => 'PRINCIPAL_WRITTEN_OFF_AMOUNT',
            'principal_write_off_amount' => 'PRINCIPAL_WRITTEN_OFF_AMOUNT',
            'nach_bounce' => 'NACH_BOUNCE',
            'monthly_income' => 'MONTHLY_INCOME',
            'is_pincode_approved' => 'APPROVED_PINCODE',
            'negative_area' => 'NEGATIVE_AREA'
        ];
        $key = isset($rejectionKeyDict[$details['key']]) ? $rejectionKeyDict[$details['key']] : $details['key'];
        if ($key == 'age_range') {
            preg_match_all('/\d+/', $details['reason'], $numbers);
            if (isset($numbers)) {
                $numbers = $numbers[0];
                if ($numbers[0] < $numbers[1]) {
                    $key = 'MIN_AGE';
                    $rules = $numbers[1];
                } else {
                    $key = 'MAX_AGE';
                    $rules = $numbers[2];
                }
            }
        } elseif ($key == 'MIN_MAX_SCORE') {
            preg_match_all('/\d+/', $details['reason'], $numbers);
            if (isset($numbers)) {
                $numbers = $numbers[0];
                $rules = ['min' => $numbers[1], 'max' => $numbers[2]];
            }
        } elseif ($key == 'MONTHLY_INCOME') {
            preg_match_all('/\d+/', $details['reason'], $numbers);
            $records = $numbers[0];
        }
        foreach ($details['log'] as $log) {
            if ($key == 'NACH_BOUNCE' && gettype($log) == "string") {
                continue;
            }
            $rules[] = $key == 'NACH_BOUNCE' && isset($log['rule']['rules']) ? $log['rule']['rules'][0] : $log['rule'];
            if (!in_array($key, ['TOTAL_PAST_DUES', 'ACCOUNT_STATUS', 'PRINCIPAL_WRITTEN_OFF_AMOUNT', 'NACH_BOUNCE'])) {
                $records[] = $key == 'NACH_BOUNCE' ? $log['records'] : $log['records'];
            }
        }
        $failLog = ['rules' => isset($rules) ? $rules : null, 'records' => isset($records) ? $records : null];
        return ['key' => $key, 'log' => $failLog];
    }
}
