<?php

namespace App\TestRunner\Tests\CRED6043;

use App\Http\Controllers\Admin\AccountingController;
use App\Services\Foreclosure\ForeclosureValidationService;
use App\TestRunner\BaseTestSuite;
use Illuminate\Http\Request;

class TestSuite extends BaseTestSuite
{
    public function jiraId(): string
    {
        return 'CRED-6043';
    }

    public function sampleInput(): array
    {
        return [
            'payment_type'     => 'foreclosure',
            'payable_amount'   => 9000,
            'bounce_charges'   => 500,
            'penal_charges'    => 0,
            'total_amount_due' => 10000,
        ];
    }

    public function custom(array $params): array
    {
        $request = new Request([
            'payment_type'     => $params['payment_type']     ?? null,
            'payable_amount'   => $params['payable_amount']   ?? null,
            'bounce_charges'   => $params['bounce_charges']   ?? null,
            'penal_charges'    => $params['penal_charges']    ?? null,
            'total_amount_due' => $params['total_amount_due'] ?? null,
        ]);

        $response = (new AccountingController())->validateForeclosureAmount($request);
        return json_decode($response->getContent(), true);
    }

    // -----------------------------------------------------------------------
    // Full suite
    // With params → dynamic assertions derived from your input
    // No params   → 28 hardcoded scenarios (CI baseline)
    // -----------------------------------------------------------------------

    protected function cases(array $params = []): array
    {
        if (!empty($params)) {
            return $this->casesFromInput($params);
        }

        return [

            // --- shouldLockPayableAmountField: is_forclosure = 1 -------------------------

            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'locks field when both interest_due and penal_charges are 0',
                'is_forclosure' => 1,
                'interest_due'  => 0,
                'penal_charges' => 0,
                'expected'      => true,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'does NOT lock when interest_due > 0 and penal_charges = 0',
                'is_forclosure' => 1,
                'interest_due'  => 500,
                'penal_charges' => 0,
                'expected'      => false,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'does NOT lock when interest_due = 0 and penal_charges > 0',
                'is_forclosure' => 1,
                'interest_due'  => 0,
                'penal_charges' => 200,
                'expected'      => false,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'does NOT lock when both interest_due and penal_charges > 0',
                'is_forclosure' => 1,
                'interest_due'  => 300,
                'penal_charges' => 150,
                'expected'      => false,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'handles string "0" values (DOM attribute format) — locks',
                'is_forclosure' => '1',
                'interest_due'  => '0',
                'penal_charges' => '0',
                'expected'      => true,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'handles string non-zero interest_due from DOM — does NOT lock',
                'is_forclosure' => '1',
                'interest_due'  => '100',
                'penal_charges' => '0',
                'expected'      => false,
                'assertType'    => 'equals',
            ],

            // --- shouldLockPayableAmountField: non-foreclosure --------------------------

            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'never locks when is_forclosure = 0',
                'is_forclosure' => 0,
                'interest_due'  => 0,
                'penal_charges' => 0,
                'expected'      => false,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'never locks when is_forclosure is null (undefined)',
                'is_forclosure' => null,
                'interest_due'  => 0,
                'penal_charges' => 0,
                'expected'      => false,
                'assertType'    => 'equals',
            ],
            [
                'suite'         => 'shouldLockPayableAmountField',
                'description'   => 'never locks when is_forclosure is empty string',
                'is_forclosure' => '',
                'interest_due'  => 0,
                'penal_charges' => 0,
                'expected'      => false,
                'assertType'    => 'equals',
            ],

            // --- validateForeclosurePayableAmount: non-foreclosure ----------------------

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'returns valid for payment_type = over_due',
                'payment_type'     => 'over_due',
                'payable_amount'   => 100,
                'bounce_charges'   => 50,
                'penal_charges'    => 50,
                'total_amount_due' => 1000,
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'returns valid for payment_type = pre_part_payment',
                'payment_type'     => 'pre_part_payment',
                'payable_amount'   => 100,
                'bounce_charges'   => 50,
                'penal_charges'    => 0,
                'total_amount_due' => 1000,
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'returns valid for payment_type = settlement_payment',
                'payment_type'     => 'settlement_payment',
                'payable_amount'   => 100,
                'bounce_charges'   => 0,
                'penal_charges'    => 50,
                'total_amount_due' => 1000,
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'returns valid when payment_type is null (undefined)',
                'payment_type'     => null,
                'payable_amount'   => 100,
                'bounce_charges'   => 0,
                'penal_charges'    => 0,
                'total_amount_due' => 5000,
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],

            // --- validateForeclosurePayableAmount: foreclosure, both charges = 0 --------

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + both charges 0 — valid for any payable amount',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 1,
                'bounce_charges'   => 0,
                'penal_charges'    => 0,
                'total_amount_due' => 5000,
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + string "0" charges (DOM attribute format) — valid',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => '1',
                'bounce_charges'   => '0',
                'penal_charges'    => '0',
                'total_amount_due' => '5000',
                'expected'         => ['valid' => true, 'minimumAmount' => null, 'alertMessage' => null],
                'assertType'       => 'equals',
            ],

            // --- validateForeclosurePayableAmount: bounce_charges > 0 -------------------
            // minimum = 10000 - 500 = 9500

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + bounce > 0 — rejects amount below minimum (9000 < 9500)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 9000,
                'bounce_charges'   => 500,
                'penal_charges'    => 0,
                'total_amount_due' => 10000,
                'expected'         => ['valid' => false, 'minimumAmount' => 9500.0, 'alertMessage' => 'The minimum amount payable is 9500'],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + bounce > 0 — rejects zero as payable amount',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 0,
                'bounce_charges'   => 500,
                'penal_charges'    => 0,
                'total_amount_due' => 10000,
                'expected'         => false,
                'assertType'       => 'keyEquals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + bounce > 0 — accepts amount exactly at minimum (9500)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 9500,
                'bounce_charges'   => 500,
                'penal_charges'    => 0,
                'total_amount_due' => 10000,
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + bounce > 0 — accepts amount above minimum (10000)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 10000,
                'bounce_charges'   => 500,
                'penal_charges'    => 0,
                'total_amount_due' => 10000,
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + bounce > 0 — alert message includes minimum amount',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 9000,
                'bounce_charges'   => 500,
                'penal_charges'    => 0,
                'total_amount_due' => 10000,
                'expected'         => 'The minimum amount payable is 9500',
                'assertType'       => 'alertMessageEquals',
            ],

            // --- validateForeclosurePayableAmount: penal_charges > 0 --------------------
            // minimum = 8000 - 300 = 7700

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + penal > 0 — rejects amount below minimum (7000 < 7700)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 7000,
                'bounce_charges'   => 0,
                'penal_charges'    => 300,
                'total_amount_due' => 8000,
                'expected'         => ['valid' => false, 'minimumAmount' => 7700.0, 'alertMessage' => 'The minimum amount payable is 7700'],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + penal > 0 — accepts amount exactly at minimum (7700)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 7700,
                'bounce_charges'   => 0,
                'penal_charges'    => 300,
                'total_amount_due' => 8000,
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],

            // --- validateForeclosurePayableAmount: both charges > 0 ---------------------
            // minimum = 15000 - (400 + 600) = 14000

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + both charges > 0 — minimum = total minus both (13000 < 14000)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 13000,
                'bounce_charges'   => 400,
                'penal_charges'    => 600,
                'total_amount_due' => 15000,
                'expected'         => ['valid' => false, 'minimumAmount' => 14000.0, 'alertMessage' => 'The minimum amount payable is 14000'],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + both charges > 0 — accepts combined minimum exactly (14000)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 14000,
                'bounce_charges'   => 400,
                'penal_charges'    => 600,
                'total_amount_due' => 15000,
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'foreclosure + both charges > 0 — accepts amount above minimum (15000)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => 15000,
                'bounce_charges'   => 400,
                'penal_charges'    => 600,
                'total_amount_due' => 15000,
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],

            // --- validateForeclosurePayableAmount: string DOM-attribute inputs -----------

            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'string inputs — below minimum fails (9000 < 9500)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => '9000',
                'bounce_charges'   => '500',
                'penal_charges'    => '0',
                'total_amount_due' => '10000',
                'expected'         => ['valid' => false, 'minimumAmount' => 9500.0, 'alertMessage' => 'The minimum amount payable is 9500'],
                'assertType'       => 'equals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'string inputs — at minimum passes (9500 = 9500)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => '9500',
                'bounce_charges'   => '500',
                'penal_charges'    => '0',
                'total_amount_due' => '10000',
                'expected'         => true,
                'assertType'       => 'keyEquals',
            ],
            [
                'suite'            => 'validateForeclosurePayableAmount',
                'description'      => 'decimal string inputs — 9500.24 < 9500.25 fails (closeTo)',
                'payment_type'     => 'foreclosure',
                'payable_amount'   => '9500.24',
                'bounce_charges'   => '500.25',
                'penal_charges'    => '0',
                'total_amount_due' => '10000.50',
                'expected'         => ['minimumAmount' => 9500.25],
                'assertType'       => 'closeTo',
            ],
        ];
    }

    protected function execute(array $case)
    {
        $svc = new ForeclosureValidationService();

        if ($case['suite'] === 'shouldLockPayableAmountField') {
            return $svc->shouldLockPayableAmountField(
                $case['is_forclosure'],
                $case['interest_due'],
                $case['penal_charges']
            );
        }

        return $svc->validateForeclosurePayableAmount(
            $case['payment_type'],
            $case['payable_amount'],
            $case['bounce_charges'],
            $case['penal_charges'],
            $case['total_amount_due']
        );
    }

    // -----------------------------------------------------------------------
    // Dynamic assertions — expected values computed from the provided input
    // -----------------------------------------------------------------------

    private function casesFromInput(array $params): array
    {
        $pt  = $params['payment_type']     ?? null;
        $pa  = (float)($params['payable_amount']   ?? 0);
        $bc  = (float)($params['bounce_charges']   ?? 0);
        $pc  = (float)($params['penal_charges']    ?? 0);
        $tad = (float)($params['total_amount_due'] ?? 0);

        $isForeclosure    = $pt === 'foreclosure';
        $hasBounceOrPenal = $bc > 0 || $pc > 0;
        $minimum          = $tad - ($bc + $pc);
        $expectedValid    = !$isForeclosure || !$hasBounceOrPenal || $pa >= $minimum;

        $base = [
            'payment_type'     => $pt,
            'payable_amount'   => $pa,
            'bounce_charges'   => $bc,
            'penal_charges'    => $pc,
            'total_amount_due' => $tad,
        ];

        $cases = [];

        // --- validateForeclosurePayableAmount assertions --------------------

        $cases[] = array_merge($base, [
            'suite'       => 'validateForeclosurePayableAmount',
            'description' => 'valid flag — expected: ' . ($expectedValid ? 'true' : 'false'),
            'expected'    => $expectedValid,
            'assertType'  => 'keyEquals',
        ]);

        $cases[] = array_merge($base, [
            'suite'       => 'validateForeclosurePayableAmount',
            'description' => 'minimumAmount — expected: ' . ($expectedValid ? 'null' : $minimum),
            'expected'    => $expectedValid ? null : $minimum,
            'assertType'  => 'minimumAmountEquals',
        ]);

        $cases[] = array_merge($base, [
            'suite'       => 'validateForeclosurePayableAmount',
            'description' => 'alertMessage — expected: ' . ($expectedValid ? 'null' : '"The minimum amount payable is ' . $minimum . '"'),
            'expected'    => $expectedValid ? null : 'The minimum amount payable is ' . $minimum,
            'assertType'  => 'alertMessageEquals',
        ]);

        // Boundary checks — only relevant when there are waivable charges
        if ($isForeclosure && $hasBounceOrPenal) {
            $cases[] = array_merge($base, [
                'suite'          => 'validateForeclosurePayableAmount',
                'description'    => 'boundary: at minimum (' . $minimum . ') should be valid',
                'payable_amount' => $minimum,
                'expected'       => true,
                'assertType'     => 'keyEquals',
            ]);

            $cases[] = array_merge($base, [
                'suite'          => 'validateForeclosurePayableAmount',
                'description'    => 'boundary: one below minimum (' . ($minimum - 1) . ') should be invalid',
                'payable_amount' => $minimum - 1,
                'expected'       => false,
                'assertType'     => 'keyEquals',
            ]);
        }

        // --- shouldLockPayableAmountField assertions ------------------------
        // Map payment_type → is_forclosure, bounce_charges → interest_due

        $expectedLock = $isForeclosure && $bc == 0 && $pc == 0;

        $cases[] = [
            'suite'         => 'shouldLockPayableAmountField',
            'description'   => 'payable amount field should ' . ($expectedLock ? '' : 'NOT ') . 'be locked',
            'is_forclosure' => $isForeclosure ? 1 : 0,
            'interest_due'  => $bc,
            'penal_charges' => $pc,
            'expected'      => $expectedLock,
            'assertType'    => 'equals',
        ];

        return $cases;
    }
}
