<?php

declare(strict_types=1);

namespace DeskMoloni\Tests\Unit;

/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 */

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\DataProvider;
use stdClass;

/**
 * CustomerMapperTest
 * 
 * Unit tests for CustomerMapper class
 * Tests data transformation between Perfex CRM and Moloni formats
 * 
 * @package DeskMoloni\Tests\Unit
 * @author Development Helper
 * @version 1.0.0
 */
#[CoversClass('CustomerMapper')]
class CustomerMapperTest extends TestCase
{
    private $customer_mapper;
    private $ci_mock;
    
    protected function setUp(): void
    {
        parent::setUp();
        
        // Mock CodeIgniter instance
        $this->ci_mock = $this->createMock(stdClass::class);
        
        // Mock get_instance function
        if (!function_exists('get_instance')) {
            function get_instance() {
                return $GLOBALS['CI_INSTANCE'];
            }
        }
        $GLOBALS['CI_INSTANCE'] = $this->ci_mock;
        
        // Create CustomerMapper instance
        require_once 'modules/desk_moloni/libraries/mappers/CustomerMapper.php';
        $this->customer_mapper = new CustomerMapper();
    }
    
    #[Test]
    #[Group('unit')]
    public function testCustomerMapperInitialization(): void
    {
        $this->assertInstanceOf(CustomerMapper::class, $this->customer_mapper);
    }
    
    #[Test]
    #[Group('unit')]
    public function testPerfexToMoloniMapping(): void
    {
        $perfex_client = [
            'userid' => '123',
            'company' => 'Test Company Ltd',
            'firstname' => 'John',
            'lastname' => 'Doe',
            'email' => 'john@testcompany.com',
            'phonenumber' => '+351999888777',
            'website' => 'https://testcompany.com',
            'vat' => 'PT999888777',
            'address' => 'Test Street 123',
            'city' => 'Porto',
            'zip' => '4000-001',
            'country' => 'PT',
            'admin_notes' => 'VIP customer'
        ];
        
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        $this->assertIsArray($moloni_data);
        $this->assertEquals('Test Company Ltd', $moloni_data['name']);
        $this->assertEquals('john@testcompany.com', $moloni_data['email']);
        $this->assertEquals('+351999888777', $moloni_data['phone']);
        $this->assertEquals('https://testcompany.com', $moloni_data['website']);
        $this->assertEquals('PT999888777', $moloni_data['vat']);
        $this->assertEquals('PT999888777', $moloni_data['number']);
        $this->assertEquals('VIP customer', $moloni_data['notes']);
        $this->assertEquals('Test Street 123', $moloni_data['address']);
        $this->assertEquals('Porto', $moloni_data['city']);
        $this->assertEquals('4000-001', $moloni_data['zip_code']);
    }
    
    #[Test]
    #[Group('unit')]
    public function testPerfexToMoloniMappingWithoutCompanyName(): void
    {
        $perfex_client = [
            'userid' => '456',
            'company' => '',
            'firstname' => 'Jane',
            'lastname' => 'Smith',
            'email' => 'jane@example.com',
            'phonenumber' => '+351888777666',
            'vat' => 'PT888777666'
        ];
        
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        // Should use firstname + lastname when company is empty
        $this->assertEquals('Jane Smith', $moloni_data['name']);
        $this->assertEquals('jane@example.com', $moloni_data['email']);
        $this->assertEquals('+351888777666', $moloni_data['phone']);
        $this->assertEquals('PT888777666', $moloni_data['vat']);
    }
    
    #[Test]
    #[Group('unit')]
    public function testPerfexToMoloniMappingWithoutVat(): void
    {
        $perfex_client = [
            'userid' => '789',
            'company' => 'No VAT Company',
            'email' => 'novat@company.com',
            'vat' => ''
        ];
        
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        // Should use userid as number when VAT is empty
        $this->assertEquals('789', $moloni_data['number']);
        $this->assertEquals('', $moloni_data['vat']);
    }
    
    #[Test]
    #[Group('unit')]
    public function testMoloniToPerfexMapping(): void
    {
        $moloni_customer = [
            'customer_id' => '555',
            'name' => 'Moloni Test Company',
            'email' => 'moloni@testcompany.com',
            'phone' => '+351777666555',
            'website' => 'https://molonittest.com',
            'vat' => 'PT777666555',
            'address' => 'Moloni Street 456',
            'city' => 'Lisboa',
            'zip_code' => '1000-001',
            'country_id' => '187', // Portugal
            'notes' => 'Important client'
        ];
        
        $perfex_data = $this->customer_mapper->toPerfex($moloni_customer);
        
        $this->assertIsArray($perfex_data);
        $this->assertEquals('Moloni Test Company', $perfex_data['company']);
        $this->assertEquals('moloni@testcompany.com', $perfex_data['email']);
        $this->assertEquals('+351777666555', $perfex_data['phonenumber']);
        $this->assertEquals('https://molonittest.com', $perfex_data['website']);
        $this->assertEquals('PT777666555', $perfex_data['vat']);
        $this->assertEquals('Moloni Street 456', $perfex_data['address']);
        $this->assertEquals('Lisboa', $perfex_data['city']);
        $this->assertEquals('1000-001', $perfex_data['zip']);
        $this->assertEquals('Important client', $perfex_data['admin_notes']);
    }
    
    #[Test]
    #[Group('unit')]
    #[DataProvider('invalidDataProvider')]
    public function testMappingWithInvalidData(array $input_data, string $direction): void
    {
        if ($direction === 'toMoloni') {
            $result = $this->customer_mapper->toMoloni($input_data);
        } else {
            $result = $this->customer_mapper->toPerfex($input_data);
        }
        
        $this->assertIsArray($result);
        // Should return array even with invalid input (graceful handling)
    }
    
    public static function invalidDataProvider(): array
    {
        return [
            'Empty Perfex data' => [[], 'toMoloni'],
            'Empty Moloni data' => [[], 'toPerfex'],
            'Null values Perfex' => [['company' => null, 'email' => null], 'toMoloni'],
            'Null values Moloni' => [['name' => null, 'email' => null], 'toPerfex']
        ];
    }
    
    #[Test]
    #[Group('unit')]
    public function testFieldSanitization(): void
    {
        $perfex_client = [
            'company' => '  Test Company with Spaces  ',
            'email' => '  EMAIL@UPPERCASE.COM  ',
            'phonenumber' => '  +351 999 888 777  ',
            'vat' => '  pt999888777  '
        ];
        
        $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
        
        // Check if data is properly sanitized
        $this->assertEquals('Test Company with Spaces', trim($moloni_data['name']));
        $this->assertEquals('email@uppercase.com', strtolower(trim($moloni_data['email'])));
    }
    
    #[Test]
    #[Group('unit')]
    public function testVatNumberValidation(): void
    {
        // Test Portuguese VAT validation
        $valid_vats = [
            'PT999888777',
            '999888777',
            'pt777666555'
        ];
        
        foreach ($valid_vats as $vat) {
            $perfex_client = ['vat' => $vat, 'company' => 'Test'];
            $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
            
            $this->assertNotEmpty($moloni_data['vat']);
        }
    }
    
    #[Test]
    #[Group('unit')]
    public function testEmailValidation(): void
    {
        $test_cases = [
            'valid@email.com' => true,
            'invalid-email' => false,
            'test@domain' => true, // Basic validation
            '' => false,
            null => false
        ];
        
        foreach ($test_cases as $email => $should_be_valid) {
            $perfex_client = ['company' => 'Test', 'email' => $email];
            $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
            
            if ($should_be_valid) {
                $this->assertEquals($email, $moloni_data['email']);
            } else {
                // Should handle invalid emails gracefully
                $this->assertTrue(true);
            }
        }
    }
    
    #[Test]
    #[Group('unit')]
    public function testPhoneNumberFormatting(): void
    {
        $phone_formats = [
            '+351999888777' => '+351999888777',
            '999888777' => '999888777',
            '+351 999 888 777' => '+351999888777',
            '(+351) 999-888-777' => '+351999888777'
        ];
        
        foreach ($phone_formats as $input => $expected) {
            $perfex_client = ['company' => 'Test', 'phonenumber' => $input];
            $moloni_data = $this->customer_mapper->toMoloni($perfex_client);
            
            // Phone formatting logic would be tested here
            $this->assertNotEmpty($moloni_data['phone']);
        }
    }
    
    #[Test]
    #[Group('unit')]
    public function testCountryCodeMapping(): void
    {
        $country_mappings = [
            'PT' => '187', // Portugal
            'ES' => '195', // Spain
            'FR' => '76',  // France
            'DE' => '81',  // Germany
            'UK' => '224'  // United Kingdom
        ];
        
        foreach ($country_mappings as $country_code => $expected_id) {
            $moloni_customer = [
                'name' => 'Test',
                'country_id' => $expected_id
            ];
            
            $perfex_data = $this->customer_mapper->toPerfex($moloni_customer);
            
            // Country mapping logic would be tested here
            $this->assertIsArray($perfex_data);
        }
    }
    
    #[Test]
    #[Group('unit')]
    public function testBidirectionalMapping(): void
    {
        // Test that mapping back and forth preserves essential data
        $original_perfex = [
            'company' => 'Bidirectional Test Company',
            'email' => 'bidirectional@test.com',
            'vat' => 'PT123456789'
        ];
        
        // Perfex -> Moloni -> Perfex
        $moloni_data = $this->customer_mapper->toMoloni($original_perfex);
        $back_to_perfex = $this->customer_mapper->toPerfex($moloni_data);
        
        // Essential fields should be preserved
        $this->assertEquals($original_perfex['company'], $back_to_perfex['company']);
        $this->assertEquals($original_perfex['email'], $back_to_perfex['email']);
        $this->assertEquals($original_perfex['vat'], $back_to_perfex['vat']);
    }
    
    protected function tearDown(): void
    {
        $this->customer_mapper = null;
        $this->ci_mock = null;
        
        parent::tearDown();
    }
}