/**
 * Copyright © 2012-2025 by Data Virtuality GmbH
 */
package org.teiid.util;

import org.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Integration tests for UTF-8-BOM charset with real-world scenarios
 * Tests DVCORE-8725 fix integration
 * 
 * @author Serhii Bashniak
 * @date 2025.09.16
 */
public class TestUtf8BomIntegration {

    @Test
    public void testCharsetUtilsGetCharset() {
        // Test charset name resolution with different cases
        Charset charset1 = CharsetUtils.getCharset("UTF-8-BOM");
        Charset charset2 = CharsetUtils.getCharset("utf-8-bom");
        Charset charset3 = CharsetUtils.getCharset("UTF_8_BOM");
        
        assertNotNull(charset1, "UTF-8-BOM should be recognized");
        assertNotNull(charset2, "utf-8-bom should be recognized (case insensitive)");
        assertNotNull(charset3, "UTF_8_BOM should be recognized");
        
        assertEquals(charset1, charset2, "Case should not matter");
        assertEquals(charset1, charset3, "Underscore variant should work");
    }

    @Test
    public void testRealWorldCsvData() throws Exception {
        // QA scenario: French CSV with BOM
        String csvContent = "ID;Nom;Prénom;Âge;Ville;Pays\r\n" +
                           "1;Dupont;François;25;Paris;France\r\n" +
                           "2;Martin;Céline;30;Lyon;France\r\n" +
                           "3;Girard;Étienne;42;Marseille;France\r\n";
        
        byte[] utf8Bytes = csvContent.getBytes(StandardCharsets.UTF_8);
        
        // Create BOM + content
        byte[] dataWithBom = new byte[3 + utf8Bytes.length];
        dataWithBom[0] = (byte) 0xEF;
        dataWithBom[1] = (byte) 0xBB;
        dataWithBom[2] = (byte) 0xBF;
        System.arraycopy(utf8Bytes, 0, dataWithBom, 3, utf8Bytes.length);
        
        // Test UTF-8-BOM decoding
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        String decoded = new String(dataWithBom, utf8Bom);
        
        // Verify correctness
        assertEquals(csvContent, decoded);
        assertTrue(decoded.contains("Prénom"));
        assertTrue(decoded.contains("François"));
        assertTrue(decoded.contains("Céline"));
        assertTrue(decoded.contains("Étienne"));
        assertFalse(decoded.contains("?"));
        assertFalse(decoded.contains("\uFEFF"));
        
        // Compare with regular UTF-8 (should include BOM)
        String regularUtf8 = new String(dataWithBom, StandardCharsets.UTF_8);
        assertTrue(regularUtf8.startsWith("\uFEFF"));
        assertNotEquals(csvContent, regularUtf8);
    }

    @Test
    public void testExcelExportScenario() throws Exception {
        // Simulates Excel export with BOM + special characters
        String excelData = "Product\tPrice\tDescription\r\n" +
                          "Café français\t€15.50\tDelicious café from France\r\n" +
                          "Thé anglais\t£12.00\tEnglish tea with bergamot\r\n";
        
        byte[] utf8Bytes = excelData.getBytes(StandardCharsets.UTF_8);
        byte[] bomData = new byte[3 + utf8Bytes.length];
        bomData[0] = (byte) 0xEF;
        bomData[1] = (byte) 0xBB;
        bomData[2] = (byte) 0xBF;
        System.arraycopy(utf8Bytes, 0, bomData, 3, utf8Bytes.length);
        
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        String result = new String(bomData, utf8Bom);
        
        assertEquals(excelData, result);
        assertTrue(result.contains("Café"));
        assertTrue(result.contains("Thé"));
        assertTrue(result.contains("€"));
        assertTrue(result.contains("£"));
        assertFalse(result.startsWith("\uFEFF"));
    }

    @Test
    public void testEdgeCaseEmpty() throws Exception {
        // Edge case: only BOM, no content
        byte[] bomOnly = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
        
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        String result = new String(bomOnly, utf8Bom);
        
        assertEquals("", result);
        assertEquals(0, result.length());
    }

    @Test
    public void testEdgeCaseCorruptedBom() throws Exception {
        // Edge case: corrupted BOM
        byte[] corruptedBom = {(byte) 0xEF, (byte) 0xBB, (byte) 0xFF, 'A'};
        
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        
        try {
            String result = new String(corruptedBom, utf8Bom);
            // If no exception, should not be clean "A"
            assertNotEquals("A", result);
        } catch (Exception e) {
            // Acceptable to throw exception for malformed input
            assertTrue(true, "Correctly detected malformed input");
        }
    }

    @Test
    public void testLargeFileSimulation() throws Exception {
        // Simulate large file processing
        StringBuilder largeContent = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            largeContent.append("Line ").append(i).append(": Données françaises avec accents éèàùç\r\n");
        }
        String expected = largeContent.toString();
        
        byte[] utf8Bytes = expected.getBytes(StandardCharsets.UTF_8);
        byte[] bomData = new byte[3 + utf8Bytes.length];
        bomData[0] = (byte) 0xEF;
        bomData[1] = (byte) 0xBB;
        bomData[2] = (byte) 0xBF;
        System.arraycopy(utf8Bytes, 0, bomData, 3, utf8Bytes.length);
        
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        String result = new String(bomData, utf8Bom);
        
        assertEquals(expected, result);
        assertTrue(result.contains("françaises"));
        assertTrue(result.contains("éèàùç"));
        assertFalse(result.startsWith("\uFEFF"));
        // Count lines by counting occurrences of \r\n
        int lineCount = 0;
        int index = 0;
        while ((index = result.indexOf("\r\n", index)) != -1) {
            lineCount++;
            index += 2;
        }
        assertEquals(1000, lineCount);
    }

    @Test
    public void testCharsetContains() throws Exception {
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        
        // Test contains method
        assertTrue(utf8Bom.contains(StandardCharsets.UTF_8));
        assertTrue(utf8Bom.contains(StandardCharsets.US_ASCII));
    }

    @Test
    public void testMultipleSequentialDecoding() throws Exception {
        Charset utf8Bom = CharsetUtils.getCharset("UTF-8-BOM");
        
        // First decoding
        byte[] data1 = {(byte)0xEF, (byte)0xBB, (byte)0xBF, 'A', 'B', 'C'};
        String result1 = new String(data1, utf8Bom);
        assertEquals("ABC", result1);
        
        // Second decoding (new instance)
        byte[] data2 = {(byte)0xEF, (byte)0xBB, (byte)0xBF, 'X', 'Y', 'Z'};
        String result2 = new String(data2, utf8Bom);
        assertEquals("XYZ", result2);
        
        // Third decoding without BOM
        byte[] data3 = {'1', '2', '3'};
        String result3 = new String(data3, utf8Bom);
        assertEquals("123", result3);
    }
}