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

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.teiid.core.crypto.FipsUtil.FipsMode;
import org.teiid.net.TeiidURL;

import javax.crypto.Cipher;
import java.sql.SQLException;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
 * Test class for FIPS mode functionality.
 */
public class TestFipsMode {
    private Properties props;

    @BeforeEach
    public void setUp() {
        props = new Properties();
    }

    @Test
    public void testFipsModeDisabledByDefault() throws SQLException {
        FipsManager.initializeFipsMode(props);
        assertThat(FipsManager.isFipsModeEnabled()).isFalse();
        assertThat(FipsManager.getCurrentFipsProvider()).isNull();
    }

    @Test
    public void testFipsModeEnabledWithDefaultProvider() throws SQLException {
        String providerName = "BCFIPS";

        props.setProperty(TeiidURL.CONNECTION.FIPS, "enabled");

        FipsManager.initializeFipsMode(props);

        assertThat(FipsManager.isFipsModeEnabled()).isTrue();
        assertThat(FipsManager.getCurrentFipsProvider()).isEqualTo(providerName);
    }

    @Test
    public void testFipsModeOnAndOff() throws SQLException {
        String providerName = "BCFIPS";

        props.setProperty(TeiidURL.CONNECTION.FIPS, "enabled");

        FipsManager.initializeFipsMode(props);

        assertThat(FipsManager.isFipsModeEnabled()).isTrue();
        assertThat(FipsManager.getCurrentFipsProvider()).isEqualTo(providerName);

        props.remove(TeiidURL.CONNECTION.FIPS);

        FipsManager.initializeFipsMode(props);

        assertThat(FipsManager.isFipsModeEnabled()).isFalse();
        assertThat(FipsManager.getCurrentFipsProvider()).isNull();
    }

    @Test
    public void testFipsModeEnabledWithSystemProvider() throws SQLException {
        String providerName = "SunPKCS11";

        props.setProperty(TeiidURL.CONNECTION.FIPS, "enabled");
        props.setProperty(TeiidURL.CONNECTION.FIPS_PROVIDER, providerName);

        FipsManager.initializeFipsMode(props);

        assertThat(FipsManager.isFipsModeEnabled()).isTrue();
        assertThat(FipsManager.getCurrentFipsProvider()).isEqualTo(providerName);
    }

    @Test
    public void testFipsModeWithInvalidProvider() {
        props.setProperty(TeiidURL.CONNECTION.FIPS, "enabled");
        props.setProperty(TeiidURL.CONNECTION.FIPS_PROVIDER, "NonExistentProvider");

        assertThatThrownBy(() -> FipsManager.initializeFipsMode(props))
                .isInstanceOf(SQLException.class)
                .hasMessageContaining("NonExistentProvider");
    }

    @Test
    public void testTeiidDataSourceFipsProperties() {
        TeiidDataSource ds = new TeiidDataSource();

        ds.setDatabaseName("TestDB");

        assertThat(ds.getFips()).isEqualTo(FipsMode.disabled);
        assertThat(ds.getFipsProvider()).isEqualTo("BCFIPS");

        ds.setFips(FipsMode.enabled);
        ds.setFipsProvider("CustomProvider");

        assertThat(ds.getFips()).isEqualTo(FipsMode.enabled);
        assertThat(ds.getFipsProvider()).isEqualTo("CustomProvider");

        Properties props = ds.buildProperties(null, null);
        assertThat(props.getProperty(TeiidURL.CONNECTION.FIPS)).isEqualTo("enabled");
        assertThat(props.getProperty(TeiidURL.CONNECTION.FIPS_PROVIDER)).isEqualTo("CustomProvider");
    }

    @Test
    public void testCipherWithFipsProvider() throws Exception {
        String providerName = "BCFIPS";
        props.setProperty(TeiidURL.CONNECTION.FIPS, "enabled");
        FipsManager.initializeFipsMode(props);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", providerName);
        assertThat(FipsManager.getCurrentFipsProvider()).isEqualTo(providerName);
        assertThat(cipher.getProvider().getName()).isEqualTo(providerName);
    }
}
