<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Imports\AutoTraderApiToVehicleImport;
use App\Jobs\AutoTraderCSVExportJob;
use App\Modules\Stock\AutoTraderStock;
use App\Services\AutoTraderHub;
use Carbon\Carbon;
use Illuminate\Support\Facades\Queue;
use Mockery;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class AutoTraderStockTest extends TenantTestCase
{
    private function makeSetting(string $key, mixed $value, string $type = 'boolean'): void
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'foo',
            'group' => 'foo',
            'name' => 'foo',
            'config_key' => $key,
            'value' => $value,
            'type' => $type,
        ]);
    }

    private function createInstance(
        ?AutoTraderApiToVehicleImport $import = null,
        ?AutoTraderHub $export = null
    ): AutoTraderStock {
        return new AutoTraderStock(
            $import ?? Mockery::mock(AutoTraderApiToVehicleImport::class),
            $export ?? Mockery::mock(AutoTraderHub::class),
        );
    }

    public function testEnabledWhenStockEnabled()
    {
        $this->makeSetting('stock-auto-trader-enabled', true);
        $this->makeSetting('sales-channels-auto-trader-enabled', false);

        $this->assertTrue($this->createInstance()->enabled());
    }

    public function testEnabledWhenSalesChannelEnabled()
    {
        $this->makeSetting('stock-auto-trader-enabled', false);
        $this->makeSetting('sales-channels-auto-trader-enabled', true);

        $this->assertTrue($this->createInstance()->enabled());
    }

    public function testDisabledWhenBothDisabled()
    {
        $this->makeSetting('stock-auto-trader-enabled', false);
        $this->makeSetting('sales-channels-auto-trader-enabled', false);

        $this->assertFalse($this->createInstance()->enabled());
    }

    public function testName()
    {
        $this->assertEquals('AutoTrader', $this->createInstance()->name());
    }

    public function testDealershipAdditionalDataFields()
    {
        $fields = $this->createInstance()->dealershipAdditionalDataFields();
        $this->assertArrayHasKey('auto-trader-location-id', $fields);
    }

    public function testLoadDealerships()
    {
        Dealership::factory()->create(['data' => ['auto-trader-location-id' => 'AT-LOC-1']]);
        Dealership::factory()->create(['data' => ['auto-trader-location-id' => 'AT-LOC-2']]);
        Dealership::factory()->create(['data' => []]); // No AT location

        $stock = $this->createInstance();
        $dealerships = $stock->loadDealerships();

        $this->assertEquals(2, $dealerships->count());
        $this->assertTrue($dealerships->values()->contains('AT-LOC-1'));
        $this->assertTrue($dealerships->values()->contains('AT-LOC-2'));
    }

    public function testLoadDealershipsExcludesNullLocations()
    {
        Dealership::factory()->create(['data' => ['auto-trader-location-id' => null]]);
        Dealership::factory()->create(['data' => ['other-field' => 'value']]);

        $stock = $this->createInstance();
        $dealerships = $stock->loadDealerships();

        $this->assertEquals(0, $dealerships->count());
    }

    public function testIsRecentlyUpdated()
    {
        $stock = $this->createInstance();
        $method = new \ReflectionMethod(AutoTraderStock::class, 'isRecentlyUpdated');
        $method->setAccessible(true);

        $recentData = [
            'metadata' => [
                'lastUpdatedByAdvertiser' => Carbon::now()->subHours(2)->toIso8601String(),
            ],
        ];
        $this->assertTrue($method->invoke($stock, $recentData));

        $oldData = [
            'metadata' => [
                'lastUpdatedByAdvertiser' => Carbon::now()->subHours(48)->toIso8601String(),
            ],
        ];
        $this->assertFalse($method->invoke($stock, $oldData));
    }

    public function testIsRecentlyUpdatedWithInvalidDate()
    {
        $stock = $this->createInstance();
        $method = new \ReflectionMethod(AutoTraderStock::class, 'isRecentlyUpdated');
        $method->setAccessible(true);

        // Invalid date should return true (safe default)
        $invalidData = [
            'metadata' => [
                'lastUpdatedByAdvertiser' => 'not-a-date',
            ],
        ];
        $this->assertTrue($method->invoke($stock, $invalidData));
    }

    public function testSetAdvertFieldsPublished()
    {
        $stock = $this->createInstance();
        $result = $stock->setAdvertFields(true);

        $this->assertEquals('PUBLISHED', $result['autotraderAdvert']);
        $this->assertEquals('PUBLISHED', $result['profileAdvert']);
    }

    public function testSetAdvertFieldsNotPublished()
    {
        $stock = $this->createInstance();
        $result = $stock->setAdvertFields(false);

        $this->assertEquals('NOT_PUBLISHED', $result['autotraderAdvert']);
        $this->assertEquals('NOT_PUBLISHED', $result['profileAdvert']);
    }

    public function testRunAfterStockSyncWhenNotFtp()
    {
        $this->makeSetting('sales-channels-auto-trader-method', 'api', 'string');
        $this->assertTrue($this->createInstance()->runAfterStockSync());
    }

    public function testRunAfterStockSyncWhenFtp()
    {
        $this->makeSetting('sales-channels-auto-trader-method', 'ftp', 'string');
        $this->assertFalse($this->createInstance()->runAfterStockSync());
    }

    public function testExportViaFtpDispatchesJobAtCorrectHours()
    {
        Queue::fake();
        $this->makeSetting('sales-channels-auto-trader-method', 'ftp', 'string');
        $this->makeSetting('sales-channels-auto-trader-enabled', true);

        Carbon::setTestNow(Carbon::create(2025, 6, 15, 8, 0, 0)); // Monday 8am

        $stock = $this->createInstance();
        $stock->runScheduledExport();

        Queue::assertPushed(AutoTraderCSVExportJob::class);

        Carbon::setTestNow();
    }

    public function testExportViaFtpDoesNotDispatchAtWrongHours()
    {
        Queue::fake();
        $this->makeSetting('sales-channels-auto-trader-method', 'ftp', 'string');
        $this->makeSetting('sales-channels-auto-trader-enabled', true);

        Carbon::setTestNow(Carbon::create(2025, 6, 15, 10, 0, 0)); // Monday 10am - not in [8,11,14,18]

        $stock = $this->createInstance();
        $stock->runScheduledExport();

        Queue::assertNotPushed(AutoTraderCSVExportJob::class);

        Carbon::setTestNow();
    }

    public function testImportMarksVehiclesAndCleansUp()
    {
        Queue::fake();
        $this->makeSetting('stock-auto-trader-enabled', true);
        $this->makeSetting('auto-trader-stock-remove-old-vehicles', true);

        $import = Mockery::mock(AutoTraderApiToVehicleImport::class);
        $import->shouldReceive('getProviderName')->andReturn('auto-trader');

        $export = Mockery::mock(AutoTraderHub::class);

        // Create a vehicle that should be cleaned up
        Vehicle::factory()->create([
            'stock_provider' => 'auto-trader',
            'uuid' => 'OLD-AT',
            'was_recently_synced' => false,
        ]);

        // No dealerships = no vehicles fetched, but cleanup should still run
        $stock = new AutoTraderStock($import, $export);
        $stock->runScheduledImport();

        // Old vehicle should be removed since was_recently_synced = 0
        $this->assertFalse(Vehicle::query()->where('uuid', 'OLD-AT')->exists());
    }

    public function testImportDoesNotRemoveOldWhenSettingDisabled()
    {
        Queue::fake();
        $this->makeSetting('stock-auto-trader-enabled', true);
        $this->makeSetting('auto-trader-stock-remove-old-vehicles', false);

        $import = Mockery::mock(AutoTraderApiToVehicleImport::class);
        $import->shouldReceive('getProviderName')->andReturn('auto-trader');

        $export = Mockery::mock(AutoTraderHub::class);

        Vehicle::factory()->create([
            'stock_provider' => 'auto-trader',
            'uuid' => 'OLD-AT',
            'was_recently_synced' => false,
        ]);

        $stock = new AutoTraderStock($import, $export);
        $stock->runScheduledImport();

        // Old vehicle should NOT be removed
        $this->assertTrue(Vehicle::query()->where('uuid', 'OLD-AT')->exists());
    }
}
