<?php

namespace App;

use App\PirimidBankAnalysis;
use Illuminate\Http\Request;
use App\Logging\CloudWatchLoggerFactory;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use App\ConsumerApplication;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Grade\AutoRejection;

class Pirimid {

    public $response;
    public $curlData;
    public $request;
    public $baseURL;
    public $API_KEY;
    public $cloudwatchLogger;

    public function __construct(Request $request){
        $this->request = $request;
        $this->baseURL = env('PIRIMID_URL').'/fiu/api/'.env('PIRIMID_TENANT_ID');
        $this->API_KEY = env('PIRIMID_API_KEY');
        $this->cloudwatchLogger = new CloudWatchLoggerFactory();
    }

    public function uploadBankStatement($requestFile=true) {
        try {
            $this->curlData = $this->postData($requestFile);
            $curl = curl_init();
            $url = $this->baseURL.'/bank-statement/process-work-order';
            if(isset($this->curlData["file"]->mime) && $this->curlData["file"]->mime == 'application/zip'){
                $url = $url.'/zip';
            }
            $headers = [
                "Content-Type: multipart/form-data",
                "Accept: */*",
                "Cookie: AWSALB=i8DzM0l2n6ER4HTDMlKsIqRs/24Dy2+8U3mIe9suO62jx0zuNsHe6AUVFKUXRCmx6sJk9IV23MHoj1kKEol+6X7SXwVrMkwVwLcg++TJghYJ62e7OtOBeQu2PJ6B; AWSALBCORS=i8DzM0l2n6ER4HTDMlKsIqRs/24Dy2+8U3mIe9suO62jx0zuNsHe6AUVFKUXRCmx6sJk9IV23MHoj1kKEol+6X7SXwVrMkwVwLcg++TJghYJ62e7OtOBeQu2PJ6B; JSESSIONID=B93B53DA9070D9A9BA35408B8341BEF1",
                "API_KEY: ".$this->API_KEY
            ];
            curl_setopt_array($curl, [
                CURLOPT_URL => $url,
                CURLOPT_POST => 1,
                CURLOPT_RETURNTRANSFER => 1,
                CURLOPT_HTTPHEADER => $headers,
                CURLOPT_FRESH_CONNECT => 1,
                CURLOPT_FORBID_REUSE => 1,
                CURLOPT_TIMEOUT => 100,
                CURLOPT_POSTFIELDS => $this->curlData,
            ]);
            $this->response = curl_exec ($curl);
            curl_close ($curl);
            // $this->response = '{"trackingId":"01957ec1-3799-6626-629c-5a05b1cd495a","status":"PENDING","timestamp":"2025-03-10T06:32:26.794Z","message":"Request Initiated"}';
            $this->saveToDB();
            return json_decode($this->response);
        } catch (\Exception $e) {
            $this->cloudwatchLogger->logger(json_encode(['title' => 'Pirimid Upload Statement', 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
        }
    }

    public function fetchAnalytics($trackingId, $type) {
        $curl = curl_init();
        $headers = [
            "Accept: application/octet-stream",
            "Cookie: AWSALB=i8DzM0l2n6ER4HTDMlKsIqRs/24Dy2+8U3mIe9suO62jx0zuNsHe6AUVFKUXRCmx6sJk9IV23MHoj1kKEol+6X7SXwVrMkwVwLcg++TJghYJ62e7OtOBeQu2PJ6B; AWSALBCORS=i8DzM0l2n6ER4HTDMlKsIqRs/24Dy2+8U3mIe9suO62jx0zuNsHe6AUVFKUXRCmx6sJk9IV23MHoj1kKEol+6X7SXwVrMkwVwLcg++TJghYJ62e7OtOBeQu2PJ6B; JSESSIONID=B93B53DA9070D9A9BA35408B8341BEF1",
            "API_KEY: ".$this->API_KEY
        ];
        curl_setopt_array($curl, [
            CURLOPT_URL => $this->baseURL."/analytics/".$type.'/download?trackingId='.$trackingId,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_FRESH_CONNECT => 1,
            CURLOPT_FORBID_REUSE => 1,
            CURLOPT_TIMEOUT => 100
        ]);
        $response = curl_exec ($curl);
        curl_close ($curl);
        return $response;
    }

    public function postData($requestFile) {
        $data = $this->request->all();
        if ($requestFile) {
            $cfile = curl_file_create(
                $data['uploaded_file']->getPathname(),
                $data['uploaded_file']->getMimeType(),
                $data['uploaded_file']->getClientOriginalName()
            );
        } else {
            $cfile = curl_file_create(
                $data['uploaded_file']->getPathname(),
                $data['uploaded_file']->getMimeType(),
                $data['uploaded_file']->getFileName()
            );
        }
        $returnData = ['file' => $cfile];

        if (isset($data['employmentType']) && $data['employmentType'] != 'SALARIED') {
            $returnData = array_merge($returnData, ['employmentType' => 'SELF_EMPLOYED']);
        }
        if (isset($data['passwords_list']) && !empty($data['passwords_list'])) {
            if (is_array($data['passwords_list'])) {
                $returnData['pdfPasswords'] = implode(',', $data['passwords_list']);
            } else {
                $returnData['pdfPasswords'] = $data['passwords_list'];
            }
        }
        return $returnData;
    }

    public function processWebhook() {
        try {
            $data = $this->request->all();
            $trackingId = $data['trackingId'];
            $pirimidAnalysis = PirimidBankAnalysis::where('tracking_id', $trackingId)
                ->orderBy('created_at', 'desc')
                ->first(['application_id', 'applicant_type']);      

            if (!$pirimidAnalysis) {
                $this->cloudwatchLogger->logger(json_encode(['title' => 'Pirimid Webhook Error', 'message' => 'Tracking ID not found in database.', 'tracking_id' => $trackingId]));
                return false;
            }

            $id = $pirimidAnalysis->application_id; 
            $applicant_type = $pirimidAnalysis->applicant_type; 

            if (isset($data['message']) && $data['message']['reportStatus'] == "COMPLETED") {
                $s3 = Storage::disk('s3');
                // Excel file save
                $excelStream = $this->fetchAnalytics($trackingId, 'excel');
                $excelfileName = 'consumer/'.$id.'/pirimid_analysis_excel_'.$trackingId.'.xls';
                $s3->put($excelfileName, $excelStream);
                $this->saveToFile('pirimid_analysis_excel', $excelfileName, $id, $applicant_type, $trackingId);
                // JSON file save
                $jsonData = $this->fetchAnalytics($trackingId, 'json');
                $jsonfileName = 'consumer/'.$id.'/pirimid_analysis_json'.$trackingId.'.json';
                // $s3->put($jsonfileName, $jsonData, $id); // TODO - uncomment in production
                $this->saveToFile('pirimid_analysis_json', $jsonfileName, $id, $applicant_type, $trackingId);
                
                $this->cloudwatchLogger->logger(json_encode(['title' => 'Pirimid Files (json/excel) saved', 'message' => 'Rejection Bre should start after this...', 'tracking_id' => $trackingId]));

                $pba = PirimidBankAnalysis::where('tracking_id', $trackingId)
                    ->where('application_id', $id)
                    ->first();
                if ($pba && $pba->analytics_fetch != 1) {
                    $pba->analytics_fetch = 1;

                    $parsedJson = json_decode($jsonData, true);
                    if ($parsedJson) {
                        $pba->adjusted_abb = $parsedJson['analytics']['overallAnalysis']['customAbbs']['adjustedAbb2']['averageOfMonthlyAverages'] ?? 0;
                        $monthlyData = $parsedJson['analytics']['overallAnalysis']['customAbbs']['adjustedAbb2']['monthlyData'] ?? [];
                        $pba->duration_in_months = count($monthlyData);
                    }

                    $pba->save();
                    $this->scrubBankStatementFromMandatoryList($id, $applicant_type);
                    $appForDecision = ConsumerApplication::with('merchant.grade_v1')->find($id);
                    $decisionApplicable = in_array($appForDecision->state, ['in-process', 'waiting for document', 'waiting for decision', 'cf approved']);
                    if ($decisionApplicable && $appForDecision->state != 'cf approved') {
                        if ($pirimidAnalysis->applicant_type == 2) {
                            $result = (new AutoRejection($this->request))->autoRejectCoApplicantJSONBRE(false, $id, $trackingId);
                        } else {
                            $result = (new AutoRejection($this->request))->autoReject(false, $id, 'banking', $trackingId);
                        }
                        if ($result) {
                            if ($pirimidAnalysis->applicant_type == 1) {
                                $consumer_application = ConsumerApplication::find($id);
                                $consumer_application->state = "rejected";
                                $consumer_application->save();
                                $appStatus = 'rejected';
                                StatusLogs::insert([
                                    'application_id' => $id,
                                    'user_id' => 107,
                                    'status' => $appStatus,
                                    'created_at' => Carbon::now()->toDateTimeString()
                                ]);
                            }
                        }
                        $this->cloudwatchLogger->logger(json_encode(['title' => 'Auto Reject Banking','application_id' => $id, 'auto_reject_result' => $result]));
                    }
                    // Approval part decoupled
                    if ($decisionApplicable) {
                        $validStates = ["form completed", "waiting for documents", "waiting for decision", "in-process", "cf approved"];
                        $creditReportAvailable = DB::selectOne("SELECT id FROM credit_report WHERE application_id = ? AND applicant_type = ?", [$id, 1]);

                            if ($appForDecision && in_array($appForDecision->state, $validStates) && !empty($creditReportAvailable)) {
                                
                                $skipApprovalBre = false;
                                if ($appForDecision->state == 'waiting for documents' && $appForDecision->application_element) {
                                    $mandatoryList = $appForDecision->application_element->mandatory_document_list;
                                    if (!empty($mandatoryList)) {
                                        $pendingDocs = array_filter(array_map('trim', explode(',', $mandatoryList)));
                                        // Ignore 'bank_statement' (and optionally consent logs if they somehow survived)
                                        $otherDocs = array_diff($pendingDocs, ['bank_statement', 'consent_logs', 'co_app_consent_logs']);
                                        if (count($otherDocs) > 0) {
                                            $skipApprovalBre = true;
                                        }
                                    }
                                }

                                $hasBankingRule = false;
                                if (!$skipApprovalBre && $appForDecision->merchant && $appForDecision->merchant->grade_v1) {
                                    $hasBankingRule = ApprovalRule::where('grade_id', $appForDecision->merchant->grade_v1->id)
                                        ->where('status', 1)
                                        ->where('rules', 'LIKE', '%emi_multiplier_on_abb%') 
                                        ->exists();
                                }

                            if ($hasBankingRule) {
                                $conAppController = new ConsumerApplicationController();
                                $autoDecisionType = $appForDecision->state == 'cf approved' ? 'cf_banking_decision_webhook' : 'banking_decision_webhook'; // Status to not be changed when already at cf approved
                                $autoDecisionResult = $conAppController->runAutoDecision($id, $autoDecisionType);
                                if (isset($autoDecisionResult) && isset($autoDecisionResult['isApproved']) && !$autoDecisionResult['isApproved'] && $autoDecisionType != 'cf_banking_decision_webhook') {
                                    // moved to waiting for decision when autodecision returns the array, cf approved handled in autodecision function
                                    $conAppController->updateApplicationStatus($id, 'waiting for decision');
                                }
                            }
                        }
                    }
                }
            }
            return true;
        } catch (\Exception $e) {
            $this->cloudwatchLogger->logger(json_encode(['tracking_id' => $trackingId ?? null, 'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()]));
            if (isset($id)) {
                ConsumerApplicationFiles::where('id', $id)->update(['finbit_analysis_date' => Carbon::now()->toDateTimeString()]);
            }
            return false;
        }
    }

    public function saveToDB() {
        $responseArray = json_decode($this->response, true);

        $pirimidBankAnalysis = new PirimidBankAnalysis();
        $pirimidBankAnalysis->tracking_id = $responseArray['trackingId'] ?? null;
        $pirimidBankAnalysis->application_id = $this->request->get('id');
        $pirimidBankAnalysis->request = json_encode($this->curlData);
        $pirimidBankAnalysis->response = json_encode(json_decode($this->response), true);
        $pirimidBankAnalysis->user_id = Auth::user()->id;
        $pirimidBankAnalysis->created_at = Carbon::now()->toDateTimeString();
        $pirimidBankAnalysis->applicant_type = $this->request->get('applicant_type');
        $pirimidBankAnalysis->save();
    }

    private function saveToFile($fileName, $path, $id, $applicant_type, $trackingId): void
    {
        $existingFile = ConsumerApplicationFiles::where('consumer_application_id', $id)
            ->where('doc_ref_id', $trackingId)
            ->where('file_type', 'pirimid_analysis_json')
            ->first();

        if ($existingFile) {
            $existingFile->touch(); // Updates `updated_at` to current time
            return;
        }

        $consumer_application_file = new ConsumerApplicationFiles();
        $consumer_application_file->consumer_application_id = $id;
        $consumer_application_file->file_type = $fileName;
        $consumer_application_file->bank_name = '';
        $consumer_application_file->password = '';
        $consumer_application_file->accounttype = '';
        $consumer_application_file->statementtype = '';
        $consumer_application_file->statemenfilettype = '';
        $consumer_application_file->customer_id = '';
        $consumer_application_file->provider = '';
        $consumer_application_file->finbit_analysis_date = '';
        $consumer_application_file->bp_number = '';
        $consumer_application_file->accountUID = '';
        $consumer_application_file->file_path = $path;
        $consumer_application_file->doc_ref_id = $trackingId;
        $consumer_application_file->created_by = Auth::user()->id ?? 107;
        $consumer_application_file->image_score = '';
        $consumer_application_file->m_generated = 0;
        $consumer_application_file->applicant_type = $applicant_type;
        $consumer_application_file->bureau_report_type = '';
        $consumer_application_file->bureau_report_score = '';
        $consumer_application_file->is_masked = 0;
        $consumer_application_file->save();
    }

    private function scrubBankStatementFromMandatoryList($application_id, $applicant_type) {
        $element = ConsumerApplicationElement::where('application_id', $application_id)->first(['mandatory_document_list']);
        if ($element && !empty($element->mandatory_document_list)) {
            $mandatoryDocs = explode(',', $element->mandatory_document_list);
            
            // Check if valid bank statement is uploaded for this applicant type
            $query = ConsumerApplicationFiles::where('consumer_application_id', $application_id)
                        ->where('file_type', 'like', '%bank_statement%');
            if ($applicant_type == 2) {
                $query->where('file_type', 'like', '%co_applicant%');
            } else {
                $query->where('file_type', 'not like', '%co_applicant%');
            }
            
            if ($query->exists()) {
                $remainingDocs = array_filter($mandatoryDocs, function($doc) use ($applicant_type) {
                    $doc = trim($doc);
                    if (strpos($doc, 'bank_statement') !== false) {
                        // If checking applicant (1) and doc is a co_applicant doc, keep it
                        if ($applicant_type == 1 && strpos($doc, 'co_applicant') !== false) {
                            return true;
                        }
                        // If checking co-applicant (2) and doc is NOT a co_applicant doc, keep it
                        if ($applicant_type == 2 && strpos($doc, 'co_applicant') === false) {
                            return true;
                        }
                        // Otherwise, it matches our applicant_type and is a bank statement, so scrub it
                        return false; 
                    }
                    return true;
                });
                
                if (count($remainingDocs) !== count($mandatoryDocs)) {
                    ConsumerApplicationElement::where('application_id', $application_id)
                        ->update(['mandatory_document_list' => implode(',', $remainingDocs)]);
                }
            }
        }
    }

}