<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Http\Controllers\Admin\AutoDCDController;
use App\Jobs\AutoDCD;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use ReflectionMethod;
use stdClass;

class AutoDCDValidationTest extends TestCase
{
    use DatabaseTransactions;
    use AutoDCDTestHelper;

    private const PRECHECK_TEST_APPLICATION_ID = 14698;

    protected $controller;

    protected function setUp()
    {
        parent::setUp();
        $this->controller = new AutoDCDController();
    }

    private function checkValidations($appId, array $payloadOverrides = [])
    {
        $payload = new stdClass();
        $payload->application_id = $appId;
        foreach ($payloadOverrides as $key => $value) {
            $payload->{$key} = $value;
        }

        $method = new ReflectionMethod(AutoDCDController::class, 'checkValidations');
        $method->setAccessible(true);

        return $method->invoke($this->controller, $appId, $payload);
    }

    private function invokeAutoDcdValidation($methodName, $appId)
    {
        $method = new ReflectionMethod(AutoDCDController::class, $methodName);
        $method->setAccessible(true);

        return $method->invoke($this->controller, $appId);
    }

    public function testCheckValidationsSuccessFlow()
    {
        $appId = $this->createTestApplication([
            'name' => 'John Doe',
            'pan_card' => 'ABCDE1234F',
            'aadhaar_card' => '123456789012',
            'loan_amount' => 150000,
            'approved_amount' => 150000
        ]);

        $this->createApplicationElement($appId, [
            'type_of_customer' => 1, // Individual
            'reference_contact_1' => '9999999991',
            'reference_contact_2' => '9999999992',
        ]);

        // E-bill check
        $this->createUtilityValidation($appId, [
            'result' => [
                'bill_date' => Carbon::now()->subDays(10)->format('d-m-Y')
            ]
        ]);

        // Bank verification
        $this->createBankRecord($appId, [
            'result' => [
                'bankTxnStatus' => true,
                'bankResponse' => 'Transaction Successful'
            ]
        ], ['applicant_type' => 1]);

        // E-Mandate
        $this->createApplicationFile($appId, 'e mandate');

        // PAN name match
        $this->createCreditReport($appId, 1, [
            'kycResult' => [
                'firstName' => 'John',
                'lastName' => 'Doe',
            ],
        ]);

        // VKYC and live photo
        $this->createDigioVkyc($appId, 1, 'complete', 'approved');
        $this->createApplicationFile($appId, 'customer_photo', ['doc_verify' => 1]);

        // Required documents
        foreach ([
            'solar_quotation',
            'tfr',
            'credit_appraisal_memo',
            'sanction_letter',
            'merchant confirmation',
            'proforma',
            'loan_agreement_esign',
            'reference',
        ] as $fileType) {
            $this->createApplicationFile($appId, $fileType);
        }

        $result = $this->checkValidations($appId, ['has_co_applicant' => false]);

        $this->assertTrue($result);

        // Assert auto_dcd_log is updated properly
        $logCount = DB::table('auto_dcd_log')->where('application_id', $appId)->where('status', 'success')->count();
        $this->assertEquals(1, $logCount);
    }

    public function testCheckValidationsEbillFailure()
    {
        $appId = $this->createTestApplication();
        $this->createApplicationElement($appId);

        // Old E-bill check
        $this->createUtilityValidation($appId, [
            'result' => [
                'bill_date' => Carbon::now()->subMonths(3)->format('d-m-Y')
            ]
        ]);

        $result = $this->checkValidations($appId, ['has_co_applicant' => false]);

        $this->assertFalse($result);
        $log = DB::table('auto_dcd_log')->where('application_id', $appId)->latest('id')->first();
        $this->assertEquals('fail', $log->status);
        $validationResults = json_decode($log->result, true);
        $this->assertEquals('fail', $validationResults['ebill_date']['status']);
        $this->assertEquals('E-bill date is older than 2 months', $validationResults['ebill_date']['message']);

        // Ensure e-bill failure comment was added
        $commentCount = DB::table('comments')
            ->where('application_id', $appId)
            ->where('comment', 'like', '%Do the updated E-bill validation%')
            ->count();
        $this->assertEquals(1, $commentCount);
    }

    public function testCheckValidationsGeneralFailureComment()
    {
        $appId = $this->createTestApplication(['created_by' => 1]); // Assuming user ID 1 exists as advisor
        $this->createApplicationElement($appId);

        // Fail Bank Verification
        $this->createBankRecord($appId, [
            'result' => [
                'bankTxnStatus' => false,
                'bankResponse' => 'FAILED'
            ]
        ], ['applicant_type' => 1]);

        $result = $this->checkValidations($appId, ['has_co_applicant' => false]);

        $this->assertFalse($result);

        // Ensure general failure comment was added
        $commentCount = DB::table('comments')
            ->where('application_id', $appId)
            ->where('comment', 'like', '%Auto DCD failed, please check reason on Checklist page%')
            ->count();
        $this->assertEquals(1, $commentCount);

        // Check if advisor is tagged (getCommentTag logic)
        // Since we can't easily mock User::whereIn in this legacy setup without mocking the DB, 
        // we at least verify the comment existence.
    }

    public function testRequiredDocumentsTreatSolarQuotationAndProformaAsComplementary()
    {
        $appId = $this->createTestApplication();
        $this->createApplicationElement($appId);

        foreach ([
            'tfr',
            'credit_appraisal_memo',
            'sanction_letter',
            'merchant confirmation',
            'proforma',
            'loan_agreement_esign',
        ] as $fileType) {
            $this->createApplicationFile($appId, $fileType);
        }

        $this->assertTrue($this->invokeAutoDcdValidation('validateRequiredDocuments', $appId));
    }

    public function testPrecheckAndCreateJobCreatesAutoDcdJobWhenPrechecksPass()
    {
        $appId = self::PRECHECK_TEST_APPLICATION_ID;
        // $this->createTestApplication([
        //     'id' => $appId,
        //     'co_applicant_name' => null,
        // ]);
        // $this->createApplicationElement($appId, [
        //     'type_of_customer' => 1,
        //     'solar_power_type' => 1,
        // ]);
        // $this->createLoanHypothecation($appId, [
        //     'applicant_signing' => 1,
        //     'co_applicant_signing' => 0,
        // ]);

        $result = AutoDCD::precheckAndCreateJob($appId);

        $this->assertTrue($result);

        $job = DB::table('jobs')
            ->where('application_id', $appId)
            ->where('from', 'autoDCD')
            ->latest('id')
            ->first();

        $this->assertNotNull($job);

        $payload = json_decode($job->payload, true);
        $this->assertEquals($appId, $payload['application_id']);
        $this->assertEquals(1, $payload['applicant_signing']);
        $this->assertEquals(0, $payload['co_applicant_signing']);
        $this->assertFalse($payload['has_co_applicant']);
        $this->assertEquals(1, $payload['type_of_customer']);
        $this->assertEquals(1, $payload['solar_power_type']);
        $this->assertLessThanOrEqual(500000, $payload['net_loan_amount']);
    }

    public function testPrecheckAndCreateJobDoesNotCreateJobWhenCoApplicantSigningIsPending()
    {
        $appId = self::PRECHECK_TEST_APPLICATION_ID;
        // $this->createTestApplication([
        //     'id' => $appId,
        //     'co_applicant_name' => 'Jane Doe',
        // ]);
        // $this->createApplicationElement($appId, [
        //     'type_of_customer' => 1,
        //     'solar_power_type' => 1,
        // ]);
        // $this->createLoanHypothecation($appId, [
        //     'applicant_signing' => 1,
        //     'co_applicant_signing' => 0,
        // ]);

        $result = AutoDCD::precheckAndCreateJob($appId);

        $this->assertFalse($result);
        $this->assertEquals(0, DB::table('jobs')->where('application_id', $appId)->where('from', 'autoDCD')->count());
    }
}
