<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Carbon\Carbon;
use Database\Seeders\Tenant\FinanceSettingSeeder;
use Database\Seeders\Tenant\SantanderFinanceSettingSeeder;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\Finance\Config\SantanderConfig;
use Mtc\MercuryDataModels\Finance\Contracts\FinanceRequestData;
use Mtc\MercuryDataModels\Finance\FinanceServiceHelper;
use Mtc\MercuryDataModels\Finance\Santander\Models\SantanderProduct;
use Mtc\MercuryDataModels\Finance\Services\SantanderFinance;
use Tests\TenantTestCase;

class SantanderFinanceServiceTest extends TenantTestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        // Clear any cached products and truncate tables
        Cache::flush();
        $this->clearSantanderTables();
    }

    protected function clearSantanderTables(): void
    {
        SantanderProduct::truncate();
    }

    protected function seedAndConfigureSantander(string $environment = 'uat'): void
    {
        $this->seed(FinanceSettingSeeder::class);
        $this->seed(SantanderFinanceSettingSeeder::class);

        // Disable other providers to ensure Santander is selected
        Settings::update('finance-codeweavers-enabled', false);
        Settings::update('finance-ivendi-enabled', false);
        Settings::update('finance-evolution-enabled', false);

        // Global credentials via config
        Config::set('services.santander.username', 'test-user');
        Config::set('services.santander.password', 'test-pass');
        Config::set('services.santander.environment', $environment);

        // Per-tenant settings
        Settings::update('finance-santander-enabled', true);
        Settings::update('finance-santander-dealer-code', 'TEST123');
    }

    protected function makeFinanceRequest(): FinanceRequestData
    {
        return new FinanceRequestData(
            uuid: 'abc123',
            registration_number: 'SD12 ABC',
            cap_id: '1231122',
            cap_code: 'FDAB123456',
            dealer_id: 'abc123',
            engine_size: 1999,
            condition: 'new',
            registration_date: Carbon::create(2020, 1, 1),
            term: 48,
            mileage: 100000,
            annual_mileage: 10000,
            price: 25000,
            deposit: 5000,
            credit_rating: 'excellent',
        );
    }

    public function testPcpQuoteCalculation(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->successResponse(1)),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $this->assertInstanceOf(SantanderFinance::class, $provider);

        $result = $provider->calculate($this->makeFinanceRequest());

        Http::assertSent(function (Request $request) {
            return str_contains($request->url(), 'ficresuktestcert.santanderconsumer.com/QuotingTool/api/multi')
                && $request['ThirdPartyUser'] === 'test-user'
                && $request['ThirdPartyPassword'] === 'test-pass'
                && isset($request['QuoteRequestList'])
                && $request['QuoteRequestList'][0]['DealerCode'] === 'TEST123'
                && $request['QuoteRequestList'][0]['ProductId'] === 'PCP001'
                && $request['QuoteRequestList'][0]['CapCode'] === 'FDAB123456'
                && $request['QuoteRequestList'][0]['CostPrice'] == 25000
                && $request['QuoteRequestList'][0]['Period'] == 48
                && $request['QuoteRequestList'][0]['Deposit'] == 5000;
        });

        $this->assertEquals(1, $result->count());
        $finance = $result->first();
        $this->assertEquals(350.00, $finance->monthly_price);
        $this->assertEquals(48, $finance->term);
        $this->assertEquals(9.9, $finance->apr);
        $this->assertEquals(5000, $finance->total_deposit);
        $this->assertEquals(25000, $finance->cash_price);
        $this->assertEquals('santander', $finance->provider);
        $this->assertEquals('Santander PCP', $finance->product_name);
    }

    private function singlePcpProductsResponse(): array
    {
        return [
            'financeProduct' => [
                'product' => [
                    [
                        'productId' => 'PCP001',
                        'productTypeId' => 11,
                        'productDesc' => 'Personal Contract Purchase',
                        'defaultRate' => 9.9,
                    ],
                ],
            ],
        ];
    }

    public function testLiveEnvironmentUrl(): void
    {
        Http::fake([
            'https://ficresuk.santanderconsumer.com/*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->successResponse(1)),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander('live');

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $provider->calculate($this->makeFinanceRequest());

        Http::assertSent(function (Request $request) {
            return str_contains($request->url(), 'ficresuk.santanderconsumer.com');
        });
    }

    public function testServiceUnavailable(): void
    {
        Http::fake([
            'https://ficresuktestcert.santanderconsumer.com/*' => Http::response([], 500),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        $this->assertEmpty($result);
    }

    public function testNoQuotesAvailable(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->emptyResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        $this->assertEmpty($result);
    }

    public function testQuoteStatusNotSuccessful(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->failedQuoteResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        $this->assertEmpty($result);
    }

    public function testConfigReadsFromConfigAndSettings(): void
    {
        $this->seed(SantanderFinanceSettingSeeder::class);

        // Global config
        Config::set('services.santander.username', 'my-username');
        Config::set('services.santander.password', 'my-password');
        Config::set('services.santander.environment', 'live');

        // Per-tenant settings
        Settings::update('finance-santander-enabled', true);
        Settings::update('finance-santander-dealer-code', 'DEALER001');

        $config = new SantanderConfig();

        $this->assertTrue($config->enabled());
        $this->assertEquals('my-username', $config->username());
        $this->assertEquals('my-password', $config->password());
        $this->assertEquals('DEALER001', $config->dealerCode());
        $this->assertEquals('live', $config->environment());
        $this->assertEquals('https://ficresuk.santanderconsumer.com', $config->baseUrl());
    }

    public function testConfigUatEnvironment(): void
    {
        $this->seed(SantanderFinanceSettingSeeder::class);
        Config::set('services.santander.environment', 'uat');

        $config = new SantanderConfig();

        $this->assertEquals('https://ficresuktestcert.santanderconsumer.com', $config->baseUrl());
    }

    public function testAllProductTypesInSingleRequest(): void
    {
        Http::fake([
            '*products*' => Http::response($this->productsApiResponse()),
            '*multi*' => Http::response($this->multiProductResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        // Verify quote request was made with all products
        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            return count($quotes) === 5;
        });

        // Should return 5 results
        $this->assertEquals(5, $result->count());

        // Verify each product type
        $this->assertNotNull($result->get('CS'));
        $this->assertEquals('Santander CS', $result->get('CS')->product_name);

        $this->assertNotNull($result->get('LP'));
        $this->assertEquals('Santander LP', $result->get('LP')->product_name);

        $this->assertNotNull($result->get('DP'));
        $this->assertEquals('Santander DP', $result->get('DP')->product_name);

        $this->assertNotNull($result->get('PCP'));
        $this->assertEquals('Santander PCP', $result->get('PCP')->product_name);

        $this->assertNotNull($result->get('DPCP'));
        $this->assertEquals('Santander DPCP', $result->get('DPCP')->product_name);
    }

    public function testNoRequestWhenNoProductsFromApi(): void
    {
        Http::fake([
            '*products*' => Http::response($this->emptyProductsResponse()),
            '*' => Http::response($this->successResponse(1)),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        // Should have made 1 request to products API
        Http::assertSent(function (Request $request) {
            return str_contains($request->url(), '/QuotingTool/api/products');
        });

        // Should NOT have made quote request since no products
        Http::assertNotSent(function (Request $request) {
            return str_contains($request->url(), '/QuotingTool/api/multi');
        });

        $this->assertEmpty($result);
    }

    public function testFetchProductsFromApi(): void
    {
        Http::fake([
            '*products*' => Http::response($this->productsApiResponse()),
            '*multi*' => Http::response($this->multiProductResponse()),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        // Should have made request to products API first
        Http::assertSent(function (Request $request) {
            return str_contains($request->url(), '/QuotingTool/api/products')
                && $request['ThirdPartyUser'] === 'test-user'
                && $request['ThirdPartyPassword'] === 'test-pass'
                && $request['DealerProduct']['DealerCode'] === 'TEST123';
        });

        // Then should have made quote request with fetched products
        Http::assertSent(function (Request $request) {
            return str_contains($request->url(), '/QuotingTool/api/multi');
        });

        // Should return results for the fetched products
        $this->assertGreaterThan(0, $result->count());

        // Verify products were stored in database
        $this->assertEquals(5, SantanderProduct::count());
    }

    public function testProductsSyncCaching(): void
    {
        Http::fake([
            '*products*' => Http::response($this->productsApiResponse()),
            '*multi*' => Http::response($this->successResponse(1)),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        // First call - should hit API and store products
        $synced1 = $config->ensureProductsSynced();
        $this->assertTrue($synced1);
        $this->assertEquals(5, SantanderProduct::count());

        // Second call - should use cache (no additional HTTP call to products API)
        $synced2 = $config->ensureProductsSynced();
        $this->assertTrue($synced2);

        // Products API should only be called once
        $productsCalls = 0;
        Http::assertSent(function (Request $request) use (&$productsCalls) {
            if (str_contains($request->url(), '/QuotingTool/api/products')) {
                $productsCalls++;
            }
            return true;
        });
        $this->assertEquals(1, $productsCalls);
    }

    public function testParseProductsResponseWithDifferentCasing(): void
    {
        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();

        // Test with camelCase (as in documentation)
        $reflection = new \ReflectionClass($config);
        $method = $reflection->getMethod('parseAndStoreProducts');
        $method->setAccessible(true);

        $camelCaseResponse = [
            'financeProduct' => [
                'product' => [
                    ['productId' => 'P001', 'productTypeId' => 11],
                    ['productId' => 'P002', 'productTypeId' => 2],
                ],
            ],
        ];

        $result = $method->invoke($config, $camelCaseResponse);
        $this->assertTrue($result);
        $this->assertEquals(2, SantanderProduct::count());
        $this->assertNotNull(SantanderProduct::where('product_id', 'P001')->first());
        $this->assertNotNull(SantanderProduct::where('product_id', 'P002')->first());

        // Clear for next test
        $this->clearSantanderTables();

        // Test with PascalCase
        $pascalCaseResponse = [
            'FinanceProduct' => [
                'Product' => [
                    ['ProductId' => 'P003', 'ProductTypeId' => 4],
                ],
            ],
        ];

        $result = $method->invoke($config, $pascalCaseResponse);
        $this->assertTrue($result);
        $this->assertEquals(1, SantanderProduct::count());
        $this->assertNotNull(SantanderProduct::where('product_id', 'P003')->first());
    }

    public function testClearProductsCache(): void
    {
        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $cacheKey = 'santander-products-synced-' . tenant('id') . '-TEST123';

        // Put something in cache
        Cache::put($cacheKey, true, 86400);
        $this->assertTrue(Cache::has($cacheKey));

        // Clear cache
        $config->clearProductsCache();
        $this->assertFalse(Cache::has($cacheKey));
    }

    public function testRefreshProducts(): void
    {
        // Use sequence to return different responses on subsequent calls
        Http::fake([
            '*products*' => Http::sequence()
                ->push($this->singlePcpProductsResponse())
                ->push($this->productsApiResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();

        // First sync - returns 1 product
        $config->ensureProductsSynced();
        $this->assertEquals(1, SantanderProduct::count());

        // Refresh should clear cache and fetch new products - returns 5 products
        $config->refreshProducts();
        $this->assertEquals(5, SantanderProduct::count());
    }

    public function testLowestRateProductSelected(): void
    {
        // Return two PCP products with different rates
        Http::fake([
            '*products*' => Http::response([
                'financeProduct' => [
                    'product' => [
                        [
                            'productId' => 'PCP001',
                            'productTypeId' => 11,
                            'defaultRate' => 9.9,
                        ],
                        [
                            'productId' => 'PCP002',
                            'productTypeId' => 11,
                            'defaultRate' => 7.5, // Lower rate - should be selected
                        ],
                    ],
                ],
            ]),
            '*multi*' => Http::response($this->successResponse(1)),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        // Should have selected the product with lower rate (PCP002)
        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            // Should only have 1 quote (best rate for PCP)
            return count($quotes) === 1 && $quotes[0]['ProductId'] === 'PCP002';
        });
    }

    private function successResponse(int $quoteId): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => $quoteId,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.9,
                    'rate' => 8.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21800,
                    'ballon' => 8000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [
                        [
                            'months' => 1,
                            'value' => 350.00,
                        ],
                        [
                            'months' => 47,
                            'value' => 350.00,
                        ],
                    ],
                ],
            ],
        ];
    }

    private function multiProductResponse(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.9,
                    'rate' => 8.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21800,
                    'ballon' => 0,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 420.00]],
                ],
                [
                    'quoteId' => 2,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 8.9,
                    'rate' => 7.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 20800,
                    'ballon' => 0,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 400.00]],
                ],
                [
                    'quoteId' => 3,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 10.9,
                    'rate' => 9.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 22800,
                    'ballon' => 0,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 440.00]],
                ],
                [
                    'quoteId' => 4,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.9,
                    'rate' => 8.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21800,
                    'ballon' => 8000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 350.00]],
                ],
                [
                    'quoteId' => 5,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.5,
                    'rate' => 8.0,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21500,
                    'ballon' => 7000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 360.00]],
                ],
            ],
        ];
    }

    private function emptyResponse(): array
    {
        return [
            'quoteResponseList' => [],
        ];
    }

    private function failedQuoteResponse(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 0,
                    'errorMessage' => 'Vehicle not eligible for finance',
                ],
            ],
        ];
    }

    private function productsApiResponse(): array
    {
        return [
            'financeProduct' => [
                'product' => [
                    [
                        'productId' => 'API-CS-001',
                        'productTypeId' => 2,
                        'productDesc' => 'Conditional Sale',
                        'defaultRate' => 8.5,
                    ],
                    [
                        'productId' => 'API-LP-001',
                        'productTypeId' => 4,
                        'productDesc' => 'Lease Purchase',
                        'defaultRate' => 7.5,
                    ],
                    [
                        'productId' => 'API-DP-001',
                        'productTypeId' => 6,
                        'productDesc' => 'Deferred Payment',
                        'defaultRate' => 9.5,
                    ],
                    [
                        'productId' => 'API-PCP-001',
                        'productTypeId' => 11,
                        'productDesc' => 'Personal Contract Purchase',
                        'defaultRate' => 8.5,
                    ],
                    [
                        'productId' => 'API-DPCP-001',
                        'productTypeId' => 12,
                        'productDesc' => 'Deferred Personal Contract Purchase',
                        'defaultRate' => 8.0,
                    ],
                ],
            ],
        ];
    }

    private function emptyProductsResponse(): array
    {
        return [
            'financeProduct' => [
                'product' => [],
            ],
        ];
    }

    public function testBatchRequestWithMultipleVehicles(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->batchResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $batch = collect([
            new FinanceRequestData(
                uuid: 'vehicle-1',
                registration_number: 'AB12 CDE',
                cap_id: '1231122',
                cap_code: 'FDAB123456',
                dealer_id: 'dealer1',
                engine_size: 1999,
                condition: 'new',
                registration_date: Carbon::create(2020, 1, 1),
                term: 48,
                mileage: 10000,
                annual_mileage: 10000,
                price: 25000,
                deposit: 5000,
                credit_rating: 'excellent',
            ),
            new FinanceRequestData(
                uuid: 'vehicle-2',
                registration_number: 'XY34 ZZZ',
                cap_id: '9999999',
                cap_code: 'FDXY999999',
                dealer_id: 'dealer1',
                engine_size: 2000,
                condition: 'used',
                registration_date: Carbon::create(2019, 6, 15),
                term: 36,
                mileage: 30000,
                annual_mileage: 12000,
                price: 18000,
                deposit: 3000,
                credit_rating: 'good',
            ),
        ]);

        $result = $provider->batchRequest($batch);

        // Should return results keyed by registration number
        $this->assertCount(2, $result);
        $this->assertArrayHasKey('AB12 CDE', $result->toArray());
        $this->assertArrayHasKey('XY34 ZZZ', $result->toArray());

        // Each vehicle should have a FinanceResultCollection
        $this->assertInstanceOf(
            \Mtc\MercuryDataModels\Finance\Contracts\FinanceResultCollection::class,
            $result->get('AB12 CDE')
        );
        $this->assertInstanceOf(
            \Mtc\MercuryDataModels\Finance\Contracts\FinanceResultCollection::class,
            $result->get('XY34 ZZZ')
        );

        // Verify first vehicle's quote
        $vehicle1Results = $result->get('AB12 CDE');
        $this->assertEquals(1, $vehicle1Results->count());
        $this->assertEquals(350.00, $vehicle1Results->first()->monthly_price);

        // Verify second vehicle's quote
        $vehicle2Results = $result->get('XY34 ZZZ');
        $this->assertEquals(1, $vehicle2Results->count());
        $this->assertEquals(280.00, $vehicle2Results->first()->monthly_price);

        // Verify API was called with both vehicles' quotes
        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            return count($quotes) === 2
                && $quotes[0]['CapCode'] === 'FDAB123456'
                && $quotes[1]['CapCode'] === 'FDXY999999';
        });
    }

    public function testBatchRequestWithNoEligibleProducts(): void
    {
        Http::fake([
            '*products*' => Http::response($this->emptyProductsResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $batch = collect([
            $this->makeFinanceRequest(),
        ]);

        $result = $provider->batchRequest($batch);

        $this->assertCount(0, $result);
    }

    public function testBatchRequestWithEmptyBatch(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $result = $provider->batchRequest(collect());

        $this->assertCount(0, $result);

        // Should not make quote request
        Http::assertNotSent(function (Request $request) {
            return str_contains($request->url(), '/QuotingTool/api/multi');
        });
    }

    public function testBatchRequestWithPartialFailures(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->batchResponseWithFailure()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $batch = collect([
            new FinanceRequestData(
                uuid: 'vehicle-1',
                registration_number: 'AB12 CDE',
                cap_id: '1231122',
                cap_code: 'FDAB123456',
                dealer_id: 'dealer1',
                engine_size: 1999,
                condition: 'new',
                registration_date: Carbon::create(2020, 1, 1),
                term: 48,
                mileage: 10000,
                annual_mileage: 10000,
                price: 25000,
                deposit: 5000,
                credit_rating: 'excellent',
            ),
            new FinanceRequestData(
                uuid: 'vehicle-2',
                registration_number: 'FAIL123',
                cap_id: '9999999',
                cap_code: 'FAIL999999',
                dealer_id: 'dealer1',
                engine_size: 2000,
                condition: 'used',
                registration_date: Carbon::create(2019, 6, 15),
                term: 36,
                mileage: 30000,
                annual_mileage: 12000,
                price: 18000,
                deposit: 3000,
                credit_rating: 'good',
            ),
        ]);

        $result = $provider->batchRequest($batch);

        // Should only return successful vehicle
        $this->assertCount(1, $result);
        $this->assertArrayHasKey('AB12 CDE', $result->toArray());
        $this->assertArrayNotHasKey('FAIL123', $result->toArray());
    }

    public function testBatchRequestUsesUuidWhenNoRegistrationNumber(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->successResponse(1)),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        $batch = collect([
            new FinanceRequestData(
                uuid: 'vehicle-uuid-123',
                registration_number: '', // Empty registration
                cap_id: '1231122',
                cap_code: 'FDAB123456',
                dealer_id: 'dealer1',
                engine_size: 1999,
                condition: 'new',
                registration_date: Carbon::create(2020, 1, 1),
                term: 48,
                mileage: 10000,
                annual_mileage: 10000,
                price: 25000,
                deposit: 5000,
                credit_rating: 'excellent',
            ),
        ]);

        $result = $provider->batchRequest($batch);

        // Should use UUID as key since no registration number
        $this->assertCount(1, $result);
        $this->assertArrayHasKey('vehicle-uuid-123', $result->toArray());
    }

    public function testBatchRequestImplementsInterface(): void
    {
        $this->seedAndConfigureSantander();

        $provider = FinanceServiceHelper::initializeForSite();

        $this->assertInstanceOf(
            \Mtc\MercuryDataModels\Finance\Contracts\BatchRequestsQuotes::class,
            $provider
        );
    }

    private function batchResponse(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.9,
                    'rate' => 8.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21800,
                    'ballon' => 8000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [
                        ['months' => 47, 'value' => 350.00],
                        ['months' => 1, 'value' => 8000.00],
                    ],
                ],
                [
                    'quoteId' => 2,
                    'quoteStatus' => 1,
                    'period' => 36,
                    'apr' => 8.9,
                    'rate' => 7.5,
                    'deposit' => 3000,
                    'costPrice' => 18000,
                    'totalAmount' => 15800,
                    'ballon' => 5000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [
                        ['months' => 35, 'value' => 280.00],
                        ['months' => 1, 'value' => 5000.00],
                    ],
                ],
            ],
        ];
    }

    private function batchResponseWithFailure(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 9.9,
                    'rate' => 8.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 21800,
                    'ballon' => 8000,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [
                        ['months' => 47, 'value' => 350.00],
                        ['months' => 1, 'value' => 8000.00],
                    ],
                ],
                [
                    'quoteId' => 2,
                    'quoteStatus' => 0, // Failed quote
                    'errorMessage' => 'Vehicle not eligible',
                ],
            ],
        ];
    }

    public function testBatchRequestPreloadsProductsOnce(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singlePcpProductsResponse()),
            '*multi*' => Http::response($this->batchResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();

        // Create batch with multiple vehicles
        $batch = collect([
            new FinanceRequestData(
                uuid: 'vehicle-1',
                registration_number: 'AB12 CDE',
                cap_id: '1231122',
                cap_code: 'FDAB123456',
                dealer_id: 'dealer1',
                engine_size: 1999,
                condition: 'new',
                registration_date: Carbon::create(2020, 1, 1),
                term: 48,
                mileage: 10000,
                annual_mileage: 10000,
                price: 25000,
                deposit: 5000,
                credit_rating: 'excellent',
            ),
            new FinanceRequestData(
                uuid: 'vehicle-2',
                registration_number: 'XY34 ZZZ',
                cap_id: '9999999',
                cap_code: 'FDXY999999',
                dealer_id: 'dealer1',
                engine_size: 2000,
                condition: 'used',
                registration_date: Carbon::create(2019, 6, 15),
                term: 36,
                mileage: 30000,
                annual_mileage: 12000,
                price: 18000,
                deposit: 3000,
                credit_rating: 'good',
            ),
            new FinanceRequestData(
                uuid: 'vehicle-3',
                registration_number: 'QQ99 AAA',
                cap_id: '8888888',
                cap_code: 'FDQQ888888',
                dealer_id: 'dealer1',
                engine_size: 1500,
                condition: 'used',
                registration_date: Carbon::create(2021, 3, 10),
                term: 48,
                mileage: 5000,
                annual_mileage: 8000,
                price: 15000,
                deposit: 2000,
                credit_rating: 'excellent',
            ),
        ]);

        // First, ensure products are synced (this does API call + inserts)
        $config->ensureProductsSynced();

        // Now track only SELECT queries on santander_products during batch processing
        $selectQueryCount = 0;
        \Illuminate\Support\Facades\DB::listen(function ($query) use (&$selectQueryCount) {
            if (
                str_contains(strtolower($query->sql), 'select')
                && str_contains($query->sql, 'santander_products')
            ) {
                $selectQueryCount++;
            }
        });

        $result = $provider->batchRequest($batch);

        // Should have results for vehicles (2 in batch response)
        $this->assertCount(2, $result);

        // Products table should only be queried once (preload), not once per vehicle
        // With 3 vehicles, without caching we'd see 3 SELECT queries
        $this->assertEquals(1, $selectQueryCount, 'Products should be loaded only once for batch processing');
    }

    public function testLpQuoteRetriesWithMaxFinalPaymentFromErrorMessage(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singleLpProductsResponse()),
            '*multi*' => Http::sequence()
                ->push($this->lpMaxFinalPaymentErrorResponse())
                ->push($this->lpSuccessResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        // First quote request should use the full cost price as FinalPayment.
        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            return count($quotes) === 1
                && $quotes[0]['ProductId'] === 'LP001'
                && (int) $quotes[0]['FinalPayment'] === 25000;
        });

        // Retry should resubmit using the max value parsed from the error message.
        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            return count($quotes) === 1
                && $quotes[0]['ProductId'] === 'LP001'
                && (int) $quotes[0]['FinalPayment'] === 9875;
        });

        $this->assertEquals(1, $result->count());
        $lp = $result->get('LP');
        $this->assertNotNull($lp);
        $this->assertEquals('Santander LP', $lp->product_name);
        $this->assertEquals(400.00, $lp->monthly_price);
        $this->assertEquals(9875, $lp->final_payment);
    }

    public function testLpQuoteNotRetriedWhenErrorMessageHasNoMaxFinalPayment(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singleLpProductsResponse()),
            '*multi*' => Http::response([
                'quoteResponseList' => [
                    [
                        'quoteId' => 1,
                        'quoteStatus' => 0,
                        'quoteErrorMessage' => 'Vehicle not eligible',
                    ],
                ],
            ]),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->calculate($this->makeFinanceRequest());

        $multiCalls = 0;
        Http::assertSent(function (Request $request) use (&$multiCalls) {
            if (str_contains($request->url(), '/QuotingTool/api/multi')) {
                $multiCalls++;
            }
            return true;
        });
        $this->assertEquals(1, $multiCalls);
        $this->assertEmpty($result);
    }

    public function testBatchRequestRetriesLpQuotesWithMaxFinalPayment(): void
    {
        Http::fake([
            '*products*' => Http::response($this->singleLpProductsResponse()),
            '*multi*' => Http::sequence()
                ->push($this->lpMaxFinalPaymentErrorResponse())
                ->push($this->lpSuccessResponse()),
            '*' => Http::response([], 400),
        ]);

        $this->seedAndConfigureSantander();

        $config = new SantanderConfig();
        $config->clearProductsCache();

        $provider = FinanceServiceHelper::initializeForSite();
        $result = $provider->batchRequest(collect([$this->makeFinanceRequest()]));

        Http::assertSent(function (Request $request) {
            if (!str_contains($request->url(), '/QuotingTool/api/multi')) {
                return false;
            }
            $quotes = $request['QuoteRequestList'];
            return count($quotes) === 1 && (int) $quotes[0]['FinalPayment'] === 9875;
        });

        $this->assertCount(1, $result);
        $vehicleResults = $result->get('SD12 ABC');
        $this->assertNotNull($vehicleResults);
        $this->assertEquals(1, $vehicleResults->count());
        $this->assertEquals(9875, $vehicleResults->first()->final_payment);
    }

    private function singleLpProductsResponse(): array
    {
        return [
            'financeProduct' => [
                'product' => [
                    [
                        'productId' => 'LP001',
                        'productTypeId' => 4,
                        'productDesc' => 'Lease Purchase',
                        'defaultRate' => 7.5,
                    ],
                ],
            ],
        ];
    }

    private function lpMaxFinalPaymentErrorResponse(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 0,
                    'quoteErrorMessage' => 'Max Final Payment 9875',
                    'rate' => 0,
                    'costPrice' => 0,
                    'deposit' => 0,
                    'apr' => 0,
                ],
            ],
            'responseStatus' => 1,
        ];
    }

    private function lpSuccessResponse(): array
    {
        return [
            'quoteResponseList' => [
                [
                    'quoteId' => 1,
                    'quoteStatus' => 1,
                    'period' => 48,
                    'apr' => 8.9,
                    'rate' => 7.5,
                    'deposit' => 5000,
                    'costPrice' => 25000,
                    'totalAmount' => 20800,
                    'ballon' => 9875,
                    'paf' => 10,
                    'bff' => 0,
                    'payments' => [['months' => 48, 'value' => 400.00]],
                ],
            ],
        ];
    }
}
