<?php
/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 * 
 * Contract Test for desk_moloni_config table
 * 
 * This test MUST FAIL until the Config_model is properly implemented
 * Following TDD RED-GREEN-REFACTOR cycle
 * 
 * @package DeskMoloni\Tests\Contract
 */

namespace DeskMoloni\Tests\Contract;

use PHPUnit\Framework\TestCase;

class ConfigTableTest extends TestCase
{
    private $CI;
    private $db;

    protected function setUp(): void
    {
        // Initialize CodeIgniter instance
        $this->CI = &get_instance();
        $this->CI->load->database();
        $this->db = $this->CI->db;
        
        // Ensure we're in test environment
        if (ENVIRONMENT !== 'testing') {
            $this->markTestSkipped('Contract tests should only run in testing environment');
        }
    }

    /**
     * @test
     * Contract: desk_moloni_config table must exist with correct structure
     */
    public function config_table_exists_with_required_structure()
    {
        // ARRANGE: Test database table existence and structure
        
        // ACT: Query table structure
        $table_exists = $this->db->table_exists('desk_moloni_config');
        
        // ASSERT: Table must exist
        $this->assertTrue($table_exists, 'desk_moloni_config table must exist');
        
        // ASSERT: Required columns exist with correct types
        $fields = $this->db->list_fields('desk_moloni_config');
        
        $required_fields = ['id', 'setting_key', 'setting_value', 'encrypted', 'created_at', 'updated_at'];
        foreach ($required_fields as $field) {
            $this->assertContains($field, $fields, "Required field '{$field}' must exist in desk_moloni_config table");
        }
        
        // ASSERT: Check field types and constraints
        $field_data = $this->db->field_data('desk_moloni_config');
        $field_info = [];
        foreach ($field_data as $field) {
            $field_info[$field->name] = $field;
        }
        
        // Verify setting_key is unique
        $this->assertEquals('varchar', strtolower($field_info['setting_key']->type), 'setting_key must be varchar type');
        $this->assertEquals(255, $field_info['setting_key']->max_length, 'setting_key must have max_length of 255');
        
        // Verify encrypted is boolean (tinyint in MySQL)
        $this->assertEquals('tinyint', strtolower($field_info['encrypted']->type), 'encrypted must be tinyint type');
        $this->assertEquals(1, $field_info['encrypted']->default_value, 'encrypted must have default value of 0');
    }

    /**
     * @test
     * Contract: Config table must enforce unique constraint on setting_key
     */
    public function config_table_enforces_unique_setting_key()
    {
        // ARRANGE: Clean table and insert test data
        $this->db->truncate('desk_moloni_config');
        
        $test_data = [
            'setting_key' => 'test_unique_key',
            'setting_value' => 'test_value',
            'encrypted' => 0
        ];
        
        // ACT & ASSERT: First insert should succeed
        $first_insert = $this->db->insert('desk_moloni_config', $test_data);
        $this->assertTrue($first_insert, 'First insert with unique key should succeed');
        
        // ACT & ASSERT: Second insert with same key should fail
        $this->expectException(\Exception::class);
        $this->db->insert('desk_moloni_config', $test_data);
    }

    /**
     * @test
     * Contract: Config table must have proper indexes for performance
     */
    public function config_table_has_required_indexes()
    {
        // ACT: Get table indexes
        $indexes = $this->db->query("SHOW INDEX FROM desk_moloni_config")->result_array();
        
        // ASSERT: Primary key exists
        $has_primary = false;
        $has_setting_key_index = false;
        
        foreach ($indexes as $index) {
            if ($index['Key_name'] === 'PRIMARY') {
                $has_primary = true;
            }
            if ($index['Key_name'] === 'idx_setting_key') {
                $has_setting_key_index = true;
            }
        }
        
        $this->assertTrue($has_primary, 'Table must have PRIMARY KEY');
        $this->assertTrue($has_setting_key_index, 'Table must have idx_setting_key index for performance');
    }

    /**
     * @test 
     * Contract: Config table must support encrypted and non-encrypted values
     */
    public function config_table_supports_encryption_flag()
    {
        // ARRANGE: Clean table
        $this->db->truncate('desk_moloni_config');
        
        // ACT: Insert encrypted and non-encrypted test data
        $encrypted_data = [
            'setting_key' => 'oauth_access_token',
            'setting_value' => 'encrypted_token_value',
            'encrypted' => 1
        ];
        
        $plain_data = [
            'setting_key' => 'api_base_url', 
            'setting_value' => 'https://api.moloni.pt/v1',
            'encrypted' => 0
        ];
        
        $this->db->insert('desk_moloni_config', $encrypted_data);
        $this->db->insert('desk_moloni_config', $plain_data);
        
        // ASSERT: Data inserted correctly with proper encryption flags
        $encrypted_row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'oauth_access_token'])->row();
        $plain_row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'api_base_url'])->row();
        
        $this->assertEquals(1, $encrypted_row->encrypted, 'Encrypted flag must be set for sensitive data');
        $this->assertEquals(0, $plain_row->encrypted, 'Encrypted flag must be false for plain data');
    }

    /**
     * @test
     * Contract: Config table must have automatic timestamps
     */
    public function config_table_has_automatic_timestamps()
    {
        // ARRANGE: Clean table
        $this->db->truncate('desk_moloni_config');
        
        // ACT: Insert test record
        $test_data = [
            'setting_key' => 'timestamp_test',
            'setting_value' => 'test_value',
            'encrypted' => 0
        ];
        
        $this->db->insert('desk_moloni_config', $test_data);
        
        // ASSERT: Timestamps are automatically set
        $row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'timestamp_test'])->row();
        
        $this->assertNotNull($row->created_at, 'created_at must be automatically set');
        $this->assertNotNull($row->updated_at, 'updated_at must be automatically set');
        
        // ASSERT: Timestamps are recent (within last 5 seconds)
        $created_time = strtotime($row->created_at);
        $current_time = time();
        $this->assertLessThan(5, abs($current_time - $created_time), 'created_at must be recent');
    }

    /**
     * @test
     * Contract: Config table must support TEXT values for large configurations
     */
    public function config_table_supports_large_text_values()
    {
        // ARRANGE: Clean table
        $this->db->truncate('desk_moloni_config');
        
        // ACT: Insert large value (simulate large JSON configuration)
        $large_value = str_repeat('{"large_config":' . str_repeat('"test"', 1000) . '}', 10);
        
        $test_data = [
            'setting_key' => 'large_config_test',
            'setting_value' => $large_value,
            'encrypted' => 0
        ];
        
        $insert_success = $this->db->insert('desk_moloni_config', $test_data);
        
        // ASSERT: Large values can be stored
        $this->assertTrue($insert_success, 'Table must support large TEXT values');
        
        // ASSERT: Large value is retrieved correctly
        $row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'large_config_test'])->row();
        $this->assertEquals($large_value, $row->setting_value, 'Large values must be stored and retrieved correctly');
    }

    protected function tearDown(): void
    {
        // Clean up test data
        if ($this->db) {
            $this->db->where('setting_key LIKE', 'test_%');
            $this->db->or_where('setting_key LIKE', '%_test');
            $this->db->delete('desk_moloni_config');
        }
    }
}