<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Models\ImportMap as ImportMapModel;
use App\Modules\Stock\ImportMap;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class ImportMapStockTest 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,
        ]);
    }

    public function testEnabled()
    {
        $this->makeSetting('stock-file-enabled', false);
        $this->assertFalse((new ImportMap())->enabled());

        Settings::update('stock-file-enabled', true);
        $this->assertTrue((new ImportMap())->enabled());
    }

    public function testName()
    {
        $this->assertEquals('Remote stock file', (new ImportMap())->name());
    }

    public function testDealershipAdditionalDataFields()
    {
        $fields = (new ImportMap())->dealershipAdditionalDataFields();
        $this->assertArrayHasKey('custom-feed-location-id', $fields);
        $this->assertEquals('text', $fields['custom-feed-location-id']['type']);
    }

    public function testIsImportableFile()
    {
        $importMap = new ImportMap();
        $method = new \ReflectionMethod(ImportMap::class, 'isImportableFile');
        $method->setAccessible(true);

        // Set up import_map property
        $importMapProp = new \ReflectionProperty(ImportMap::class, 'import_map');
        $importMapProp->setAccessible(true);
        $importMapProp->setValue($importMap, ImportMapModel::factory()->create([
            'data' => ['file_name' => null],
        ]));

        $this->assertTrue($method->invoke($importMap, 'stock.csv'));
        $this->assertTrue($method->invoke($importMap, 'data.xls'));
        $this->assertTrue($method->invoke($importMap, 'vehicles.xlsx'));
        $this->assertTrue($method->invoke($importMap, 'archive.zip'));
        $this->assertFalse($method->invoke($importMap, 'readme.txt'));
        $this->assertFalse($method->invoke($importMap, 'image.jpg'));
        $this->assertFalse($method->invoke($importMap, 'script.php'));
    }

    public function testIsImportableFileWithSpecificFilename()
    {
        $importMap = new ImportMap();
        $method = new \ReflectionMethod(ImportMap::class, 'isImportableFile');
        $method->setAccessible(true);

        $importMapProp = new \ReflectionProperty(ImportMap::class, 'import_map');
        $importMapProp->setAccessible(true);
        $importMapProp->setValue($importMap, ImportMapModel::factory()->create([
            'data' => ['file_name' => 'specific-stock.csv'],
        ]));

        $this->assertTrue($method->invoke($importMap, 'specific-stock.csv'));
        $this->assertFalse($method->invoke($importMap, 'other-stock.csv'));
    }

    public function testIsSpecifiedFileFormat()
    {
        $importMap = new ImportMap();
        $method = new \ReflectionMethod(ImportMap::class, 'isSpecifiedFileFormat');
        $method->setAccessible(true);

        $this->assertTrue($method->invoke($importMap, 'file.csv'));
        $this->assertTrue($method->invoke($importMap, 'file.xls'));
        $this->assertTrue($method->invoke($importMap, 'file.xlsx'));
        $this->assertTrue($method->invoke($importMap, 'file.zip'));
        $this->assertFalse($method->invoke($importMap, 'file.txt'));
        $this->assertFalse($method->invoke($importMap, 'file.json'));
        $this->assertFalse($method->invoke($importMap, 'file.xml'));
    }

    public function testGetBackupFileName()
    {
        $importMap = new ImportMap();
        $method = new \ReflectionMethod(ImportMap::class, 'getBackupFileName');
        $method->setAccessible(true);

        $importMapModel = ImportMapModel::factory()->create();
        $importMapProp = new \ReflectionProperty(ImportMap::class, 'import_map');
        $importMapProp->setAccessible(true);
        $importMapProp->setValue($importMap, $importMapModel);

        $result = $method->invoke($importMap, 'stock.csv');
        $this->assertEquals($importMapModel->id . '_import.csv.bck', $result);

        $result = $method->invoke($importMap, 'data.xlsx');
        $this->assertEquals($importMapModel->id . '_import.xlsx.bck', $result);
    }

    public function testLoadImportMapsFiltersAutomated()
    {
        // Create automated and non-automated import maps
        ImportMapModel::factory()->create([
            'data' => ['automate' => true, 'protocol' => 'ftp', 'host' => 'example.com', 'username' => 'u', 'password' => 'p'],
        ]);
        ImportMapModel::factory()->create([
            'data' => ['automate' => false],
        ]);
        ImportMapModel::factory()->create([
            'data' => [],
        ]);

        $importMap = new ImportMap();
        $method = new \ReflectionMethod(ImportMap::class, 'loadImportMaps');
        $method->setAccessible(true);

        $result = $method->invoke($importMap);

        $this->assertEquals(1, $result->count());
    }

    public function testRunScheduledImportWithNoAutomatedMaps()
    {
        Queue::fake();
        $this->makeSetting('stock-file-enabled', true);

        // No import maps at all
        $importMap = new ImportMap();
        $importMap->runScheduledImport();

        // Should not throw an error
        $this->assertEquals(0, Vehicle::query()->count());
    }

    public function testAggregateStats()
    {
        $importMap = new ImportMap();
        $aggregateMethod = new \ReflectionMethod(ImportMap::class, 'aggregateStats');
        $aggregateMethod->setAccessible(true);
        $resetMethod = new \ReflectionMethod(ImportMap::class, 'resetStats');
        $resetMethod->setAccessible(true);

        $resetMethod->invoke($importMap);

        $aggregateMethod->invoke($importMap, ['created' => 3, 'updated' => 5, 'failed' => 1, 'processed' => 9]);

        $stats = $importMap->getImportStats();
        $this->assertEquals(3, $stats['created']);
        $this->assertEquals(5, $stats['updated']);
        $this->assertEquals(1, $stats['failed']);
    }

    public function testAggregateStatsAccumulates()
    {
        $importMap = new ImportMap();
        $aggregateMethod = new \ReflectionMethod(ImportMap::class, 'aggregateStats');
        $aggregateMethod->setAccessible(true);
        $resetMethod = new \ReflectionMethod(ImportMap::class, 'resetStats');
        $resetMethod->setAccessible(true);

        $resetMethod->invoke($importMap);

        $aggregateMethod->invoke($importMap, ['created' => 2, 'updated' => 3, 'failed' => 0, 'processed' => 5]);
        $aggregateMethod->invoke($importMap, ['created' => 1, 'updated' => 4, 'failed' => 2, 'processed' => 7]);

        $stats = $importMap->getImportStats();
        $this->assertEquals(3, $stats['created']);
        $this->assertEquals(7, $stats['updated']);
        $this->assertEquals(2, $stats['failed']);
    }
}
