<?php


namespace App;

use App\ApprovalRule;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\PreEligibilityController;
use App\Http\Controllers\MConnector\MerchantApiIntegration;
use App\Logging\CloudWatchLoggerFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use App\NameMatchService;


class PreEligibility
{
    private $payload;
    /**
     * @var Request
     */
    private $request;

    private $runningBRE = false;

    private $cwFactory = null;

    private static $APPLICANT = 1;
    /**
     * @var GradeController
     */
    private $gradeController = null;
    /**
     * @var string
     */
    public $error = null;
    /**
     * @var \Illuminate\Http\JsonResponse
     */
    private $bre_response = null;
    private $applicant_type = null;
    private $message = '';
    /**
     * @var string|void
     */
    private $request_id = '';
    private $finalResponse = null;
    private $webookMessage = [];

    public $applicationController;
    public $preEligibilityController;
    public $applicationDetails;
    /**
     * @var mixed
     */
    private $event = null;

    public function __construct(Request $request){
        $this->request = $request;
        $this->event = $request->get('event');
        $this->cwFactory = new CloudWatchLoggerFactory();
        $this->applicationController = new ConsumerApplicationController();
        $this->preEligibilityController = new PreEligibilityController($this->request);
        $this->applicationDetails = DB::selectOne("SELECT id, merchant_id, loan_amount from pre_eligibility_applications WHERE id = ?", [$this->request->get('id')]);
    }

    public function init(){
        $this->logger("Pre-Eligibility Bureau Started");
        $this->request_id = (new MerchantApiIntegration($this->request))->guidv4();
        $this->logger("Running For App Id: ".$this->request->get('id').', RequestId: '.$this->request_id);
        try {
            $this->runBureauService();
        }catch (\Exception $e){
            $this->logger(["Exception Found : ", $e->getMessage(), $e->getLine(), $e->getFile()], true);
        }
    }

    private function runBureauService()
    {

        $this->logger("Running Applicant Bureau");
        $this->generateApplicantBureau($this->preEligibilityController, self::$APPLICANT);

        if (!$this->runningBRE) {
            return;
        }

        $this->runMultiApprovalCheck();

        $id = $this->request->get('id');
        $payload = $this->getWebhookPayload($id, $this->finalResponse);
        $this->applicationController->webhook($id, [
            'type' => 'Pre-eligibility',
            'status' => null,
            'data' => $payload,
            'pre_eligibility' => true,
            'merchant_id' => $this->applicationDetails->merchant_id ?? null
        ]);
    }

    private function runMultiApprovalCheck()
    {
        $start = microtime(true);
        $this->logger("Running multiapprovalcheckpreeligibility");
        try {
            $this->finalResponse = $this->preEligibilityController->multiapprovalcheckpreeligibility(
                $this->request->get('id'),
                $this->request_id,
                true
            );
            $end = microtime(true);
            $this->logger("multiapprovalcheckpreeligibility Completed, " . $this->getProcessTime($end - $start) . ", Result: " . json_encode($this->finalResponse));
        } catch (\Exception $e) {
            $this->logger(["multiapprovalcheckpreeligibility Exception", $e->getMessage(), $e->getLine(), $e->getFile()], true);
        }
    }

    private function generateApplicantBureau($preEligibilityController, $applicant_type){
        $start = microtime(true);
        $response = $preEligibilityController->generateSoftBureauReport($this->request->get('id'), '', $applicant_type);
        $end = microtime(true);
        $this->logger("Bureau Response: - ". json_encode($response->getData()).', '.$this->getProcessTime($end - $start));
        if (isset($response->getData()->status) && $response->getData()->status == 'OK') {
            $this->runningBRE = true;
        }else if(isset($response->getData()->message)){
            $this->runningBRE = false;
            $this->error = $response->getData()->message;
            $id = $this->request->get('id');
            $this->message = 'Soft Bureau Failed';
            $payload = $this->getWebhookPayload($id);
            $this->applicationController->webhook($id, [
                'type' => 'Pre-eligibility',
                'status' => null,
                'data' => $payload,
                'pre_eligibility' => true,
                'merchant_id' => $this->applicationDetails->merchant_id ?? null
            ]);
        }

        return $this;
    }

    private function logger($data, $is_error = false){
        if(!_env('APP_CONNECTION')) {
            $message = is_array($data) ? json_encode($data, JSON_PRETTY_PRINT) : $data;
            if ($is_error){
                $this->event->error($message);
            }else{
                $this->event->info($message);
            }
        }
        $this->cwFactory->logger(json_encode(['data' => is_array($data) ? $data : [$data], 'application_id' => $this->request->get('id')]));
    }

    private function getProcessTime($executionTime){
        return "Execution time: " . number_format($executionTime * 1000, 2) . " ms (" . number_format($executionTime, 4) . " sec)";
    }

    public function getWebhookPayload($id, $result=null){
        $preEligibilityId = $this->applicationDetails ? (int) $this->applicationDetails->id : (int) $id;
        $appRow = DB::table('pre_eligibility_applications')->where('id', $preEligibilityId)->first(['unique_id']);
        $uniqueIdNumber = $appRow->unique_id ?? '';

        if ($this->runningBRE && isset($this->preEligibilityController->jsonBREResponse)) {
            $jsonBREResponse = $this->preEligibilityController->jsonBREResponse;
            $policyStatus = [];
            if (isset($jsonBREResponse->getData()->res)) {
                $resData = json_decode($jsonBREResponse->getData()->res, true);
                if ($resData) {
                    $policyStatus = $resData;

                    // Collect ApprovalRule ids embedded in policy-* keys (handles plain
                    // `policy-39`, `policy-power-savings-39`, `policy-adjusted-abb-39`).
                    $policyIds = [];
                    foreach ($policyStatus as $key => $_item) {
                        if (preg_match('/^policy-(?:power-savings-|adjusted-abb-)?(\d+)$/', $key, $matches)) {
                            $policyIds[$key] = (int) $matches[1];
                        }
                    }

                    $ruleNames = !empty($policyIds)
                        ? ApprovalRule::whereIn('id', array_values($policyIds))->pluck('rule_name', 'id')->toArray()
                        : [];

                    // For each policy entry: drop the `rules` payload and stamp the rule_name as `name`.
                    foreach ($policyIds as $key => $ruleId) {
                        $original = is_array($policyStatus[$key]) ? $policyStatus[$key] : [];
                        $policyStatus[$key] = [
                            'name'             => $ruleNames[$ruleId] ?? '',
                            'failed_condition' => $original['failed_condition'] ?? null,
                            'policy_status'    => $original['policy_status'] ?? false,
                        ];
                    }
                }
            }

            // Compute name match using bureau applicant details (First_Name, Last_Name)
            $nameMatchScore = 0;
            try {
                $preAppRow = DB::table('pre_eligibility_applications')
                    ->where('id', $preEligibilityId)
                    ->first(['customer_name']);

                $preName = trim($preAppRow->customer_name ?? '');
                $names = $this->preEligibilityController->getBureauApplicantNames($preEligibilityId, $jsonBREResponse);
                $bureauFirst = trim($names['first_name'] ?? '');
                $bureauLast  = trim($names['last_name'] ?? '');
                $bureauFull = trim(($bureauFirst ?: '') . ' ' . ($bureauLast ?: ''));

                if ($preName && $bureauFull) {
                    $matcher = new NameMatchService();
                    $score = $matcher->nameMatch($preName, $bureauFull);
                    $nameMatchScore = is_numeric($score) ? round($score, 2) : 0;
                }
            } catch (\Exception $ex) {
                $nameMatchScore = 0;
            }

            $offers = $this->preEligibilityController->getPreEligibilityOffers($preEligibilityId);
            $bureauValues = $this->preEligibilityController->calculateBureauMetricsFromS3($preEligibilityId);

            $payload = [
                'returnCode' => '000000',
                'preEligibilityId' => $preEligibilityId,
                'data' => [
                    'bre_execution' => true,
                    'preEligibilityId' => $preEligibilityId,
                    'policy_status' => $policyStatus,
                    'name_match' => $nameMatchScore ?? 0,
                    'total_sanction_amount' => $bureauValues['total_sanction_amount'],
                    'total_outstanding_amount' => $bureauValues['total_outstanding'],
                    'total_overdue_amount' => $bureauValues['total_overdue'],
                    'offers' => $offers,
                ],
                "type" => "Pre-eligibility",
                "status" => null,
                'uniqueIdNumber' => $uniqueIdNumber,
            ];

            return $payload;
        }
        // Soft pull failed and consent failure webhooks
        $message = $this->message;
        if (isset($this->error)) {
            if (strpos(strtolower($this->error), 'consent') !== false) {
                $message = 'Consent not available.';
            } else {
                $message = $this->message . "-" . $this->error;
            }
        }

        $payload = [
            'returnCode' => '000000',
            'preEligibilityId' => $preEligibilityId,
            'data' => [
                'preEligibilityId' => $preEligibilityId,
                'bre_execution' => false,
                'message' => $message,
            ],
            'uniqueIdNumber' => $uniqueIdNumber,
        ];

        return $payload;
    }
}
