<?php

namespace Tests\Unit\Services;

use Tests\TestCase;
use App\Services\Core\ConfigurationManager;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ConfigurationManagerTest extends TestCase
{
    use RefreshDatabase;

    private ConfigurationManager $configManager;

    protected function setUp(): void
    {
        parent::setUp();
        $this->configManager = new ConfigurationManager();
    }

    public function test_can_set_and_get_configuration()
    {
        $this->configManager->set('test.key', 'test_value');
        $result = $this->configManager->get('test.key');
        
        $this->assertEquals('test_value', $result);
    }

    public function test_can_get_with_default_value()
    {
        $result = $this->configManager->get('non.existent.key', 'default_value');
        $this->assertEquals('default_value', $result);
    }

    public function test_can_check_if_key_exists()
    {
        $this->configManager->set('existing.key', 'value');
        
        $this->assertTrue($this->configManager->has('existing.key'));
        $this->assertFalse($this->configManager->has('non.existent.key'));
    }

    public function test_can_remove_configuration()
    {
        $this->configManager->set('temp.key', 'temp_value');
        $this->assertTrue($this->configManager->has('temp.key'));
        
        $this->configManager->forget('temp.key');
        $this->assertFalse($this->configManager->has('temp.key'));
    }

    public function test_can_work_with_nested_arrays()
    {
        $config = [
            'database' => [
                'host' => 'localhost',
                'port' => 3306,
                'credentials' => [
                    'username' => 'admin',
                    'password' => 'secret'
                ]
            ]
        ];

        $this->configManager->set('app', $config);
        
        $this->assertEquals('localhost', $this->configManager->get('app.database.host'));
        $this->assertEquals(3306, $this->configManager->get('app.database.port'));
        $this->assertEquals('admin', $this->configManager->get('app.database.credentials.username'));
        $this->assertEquals($config['database'], $this->configManager->get('app.database'));
    }

    public function test_can_merge_configurations()
    {
        $config1 = [
            'feature_a' => true,
            'settings' => [
                'timeout' => 30,
                'retries' => 3
            ]
        ];

        $config2 = [
            'feature_b' => true,
            'settings' => [
                'timeout' => 60,
                'cache' => true
            ]
        ];

        $this->configManager->set('app', $config1);
        $this->configManager->merge('app', $config2);

        $this->assertTrue($this->configManager->get('app.feature_a'));
        $this->assertTrue($this->configManager->get('app.feature_b'));
        $this->assertEquals(60, $this->configManager->get('app.settings.timeout')); // Should be overridden
        $this->assertEquals(3, $this->configManager->get('app.settings.retries')); // Should be preserved
        $this->assertTrue($this->configManager->get('app.settings.cache')); // Should be added
    }

    public function test_can_get_all_configurations()
    {
        $this->configManager->set('key1', 'value1');
        $this->configManager->set('key2', 'value2');
        $this->configManager->set('nested.key', 'nested_value');

        $all = $this->configManager->all();

        $this->assertArrayHasKey('key1', $all);
        $this->assertArrayHasKey('key2', $all);
        $this->assertArrayHasKey('nested', $all);
        $this->assertEquals('value1', $all['key1']);
        $this->assertEquals('value2', $all['key2']);
        $this->assertEquals('nested_value', $all['nested']['key']);
    }

    public function test_can_load_from_file()
    {
        // Create a temporary config file
        $configPath = storage_path('temp_config.php');
        $configContent = "<?php\nreturn [\n    'test_setting' => 'file_value',\n    'nested' => [\n        'option' => true\n    ]\n];";
        file_put_contents($configPath, $configContent);

        $this->configManager->loadFromFile('file_config', $configPath);

        $this->assertEquals('file_value', $this->configManager->get('file_config.test_setting'));
        $this->assertTrue($this->configManager->get('file_config.nested.option'));

        // Clean up
        if (file_exists($configPath)) {
            unlink($configPath);
        }
    }

    public function test_can_save_to_file()
    {
        $this->configManager->set('save_test', [
            'setting1' => 'value1',
            'setting2' => ['nested' => 'value2']
        ]);

        $savePath = storage_path('saved_config.php');
        $this->configManager->saveToFile('save_test', $savePath);

        $this->assertFileExists($savePath);

        // Load the saved file and verify content
        $savedConfig = include $savePath;
        $this->assertEquals('value1', $savedConfig['setting1']);
        $this->assertEquals('value2', $savedConfig['setting2']['nested']);

        // Clean up
        if (file_exists($savePath)) {
            unlink($savePath);
        }
    }

    public function test_can_clear_all_configurations()
    {
        $this->configManager->set('key1', 'value1');
        $this->configManager->set('key2', 'value2');

        $this->assertNotEmpty($this->configManager->all());

        $this->configManager->clear();

        $this->assertEmpty($this->configManager->all());
    }

    public function test_can_handle_array_operations()
    {
        $this->configManager->set('list', ['item1', 'item2']);
        
        $this->configManager->push('list', 'item3');
        $items = $this->configManager->get('list');
        
        $this->assertCount(3, $items);
        $this->assertEquals('item3', $items[2]);
    }

    public function test_configuration_scoping()
    {
        // Test module-specific configuration scoping
        $this->configManager->setScope('module1');
        $this->configManager->set('setting', 'module1_value');
        
        $this->configManager->setScope('module2');
        $this->configManager->set('setting', 'module2_value');
        
        $this->configManager->setScope('module1');
        $this->assertEquals('module1_value', $this->configManager->get('setting'));
        
        $this->configManager->setScope('module2');
        $this->assertEquals('module2_value', $this->configManager->get('setting'));
        
        // Reset scope
        $this->configManager->setScope(null);
    }
}