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

import org.junit.jupiter.api.Test;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;

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

/**
 * Tests covering specific rejection scenarios from DVCORE-8725
 * Based on "Rejection Details" from the task description
 * <p>
 * Tests scenarios that were originally failing with "Illegal replacement error"
 * during character encoding/decoding with UTF-8-BOM.
 *
 * @author Serhii Bashniak
 * @date 2025.10.06
 */
public class TestUtf8BomRejectionScenarios {

    private Charset getUtf8BomCharset() {
        return CharsetUtils.getCharset("UTF-8-BOM");
    }

    /**
     * Test scenario from rejection: base64 to UTF-8-BOM conversion
     * Original failure: SELECT to_chars(to_bytes('UGxhaW50ZXh0IHN0cmluZw==', 'base64'), 'utf-8-bom')
     */
    @Test
    public void testBase64ToUtf8BomConversion() throws Exception {
        // "UGxhaW50ZXh0IHN0cmluZw==" decodes to "Plaintext string"
        String base64Input = "UGxhaW50ZXh0IHN0cmluZw==";
        byte[] decodedBytes = java.util.Base64.getDecoder().decode(base64Input);

        // Now encode these bytes as UTF-8-BOM
        Charset utf8Bom = getUtf8BomCharset();
        CharsetEncoder encoder = utf8Bom.newEncoder();

        String plaintext = new String(decodedBytes, StandardCharsets.UTF_8);
        assertEquals("Plaintext string", plaintext);

        // Encode to UTF-8-BOM
        CharBuffer input = CharBuffer.wrap(plaintext);
        ByteBuffer output = ByteBuffer.allocate(100);

        CoderResult result = encoder.encode(input, output, true);
        assertEquals(CoderResult.UNDERFLOW, result);

        // Flush the encoder
        result = encoder.flush(output);
        assertEquals(CoderResult.UNDERFLOW, result);

        output.flip();
        byte[] encodedBytes = new byte[output.remaining()];
        output.get(encodedBytes);

        // Should start with BOM
        assertEquals((byte) 0xEF, encodedBytes[0]);
        assertEquals((byte) 0xBB, encodedBytes[1]);
        assertEquals((byte) 0xBF, encodedBytes[2]);

        // And when decoded back, should give us the original string
        String decoded = new String(encodedBytes, utf8Bom);
        assertEquals("Plaintext string", decoded);
    }

    /**
     * Test French characters that were failing in the original rejection
     * Original failure: Character 'é' causing illegal replacement errors
     */
    @Test
    public void testFrenchCharactersWithBom() throws Exception {
        String frenchText = "café résumé naïve";
        Charset utf8Bom = getUtf8BomCharset();

        // Encode with BOM
        byte[] encoded = frenchText.getBytes(utf8Bom);

        // Should start with BOM
        assertEquals((byte) 0xEF, encoded[0]);
        assertEquals((byte) 0xBB, encoded[1]);
        assertEquals((byte) 0xBF, encoded[2]);

        // Decode back
        String decoded = new String(encoded, utf8Bom);
        assertEquals(frenchText, decoded);

        // Ensure no replacement characters
        assertFalse(decoded.contains("\uFFFD"), "Should not contain replacement characters");
    }


    /**
     * Test edge case: file with only BOM and no content
     */
    @Test
    public void testBomOnlyFile() throws Exception {
        byte[] bomOnly = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};

        Charset utf8Bom = getUtf8BomCharset();
        String decoded = new String(bomOnly, utf8Bom);

        assertEquals("", decoded);
        assertEquals(0, decoded.length());
    }

    /**
     * Test mixed content: ASCII + European chars + Asian chars
     * This was failing in the original implementation
     */
    @Test
    public void testMixedContentWithBom() throws Exception {
        String mixedText = "Hello 世界 café Москва";
        Charset utf8Bom = getUtf8BomCharset();

        // Encode with BOM
        byte[] encoded = mixedText.getBytes(utf8Bom);

        // Should start with BOM
        assertEquals((byte) 0xEF, encoded[0]);
        assertEquals((byte) 0xBB, encoded[1]);
        assertEquals((byte) 0xBF, encoded[2]);

        // Decode back
        String decoded = new String(encoded, utf8Bom);
        assertEquals(mixedText, decoded);

        // Ensure all characters are preserved
        assertTrue(decoded.contains("Hello"));
        assertTrue(decoded.contains("世界"));
        assertTrue(decoded.contains("café"));
        assertTrue(decoded.contains("Москва"));

        // Ensure no replacement characters
        assertFalse(decoded.contains("\uFFFD"), "Should not contain replacement characters");
    }
}