/**
 * Copyright (c) 2025 SoftCorporation LLC. All rights reserved.
 *
 * The Software License, Version 1.0
 *
 * SoftCorporation LLC. grants you ("Licensee") a non-exclusive, royalty free,
 * license to use, modify and redistribute this software in source and binary
 * code form, provided that the following conditions are met:
 *
 * 1. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        SoftCorporation LLC. (http://www.softcorporation.com)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 2. This software and SoftCorporation name must not be used to
 *    promote products derived from the software without prior
 *    written permission. For written permission, please contact
 *    info@softcorporation.com.
 *
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
 * IN NO EVENT SHALL THE SOFTCORPORATION BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION).
 *
 */
package com.softcorporation.sandi.base.service.solr;

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

import java.io.IOException;
import java.util.Arrays;

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.common.SolrDocument;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;

/**
 * Unit tests for SolrService
 */
class SolrServiceTest {

    private SolrService solrService;

    @BeforeEach
    void setUp() {
        solrService = new SolrService();
        
        // Set test configuration values
        ReflectionTestUtils.setField(solrService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(solrService, "username", "testuser");
        ReflectionTestUtils.setField(solrService, "password", "testpass");
        ReflectionTestUtils.setField(solrService, "connectionTimeout", 5000);
        ReflectionTestUtils.setField(solrService, "socketTimeout", 30000);
    }

    @Test
    void testGetString_WithValidStringValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", "test value");

        // Act
        String result = solrService.getString(doc, "testField");

        // Assert
        assertEquals("test value", result);
    }

    @Test
    void testGetString_WithNullValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", null);

        // Act
        String result = solrService.getString(doc, "testField");

        // Assert
        assertNull(result);
    }

    @Test
    void testGetString_WithNonExistentField() {
        // Arrange
        SolrDocument doc = new SolrDocument();

        // Act
        String result = solrService.getString(doc, "nonExistentField");

        // Assert
        assertNull(result);
    }

    @Test
    void testGetString_WithIntegerValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", 123);

        // Act
        String result = solrService.getString(doc, "testField");

        // Assert
        assertEquals("123", result);
    }

    @Test
    void testGetString_WithListValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", Arrays.asList("value1", "value2"));

        // Act
        String result = solrService.getString(doc, "testField");

        // Assert
        assertEquals("[value1, value2]", result);
    }

    @Test
    void testGetInteger_WithValidIntegerValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", 42);

        // Act
        Integer result = solrService.getInteger(doc, "testField");

        // Assert
        assertEquals(Integer.valueOf(42), result);
    }

    @Test
    void testGetInteger_WithValidStringValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", "123");

        // Act
        Integer result = solrService.getInteger(doc, "testField");

        // Assert
        assertEquals(Integer.valueOf(123), result);
    }

    @Test
    void testGetInteger_WithInvalidStringValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", "not-a-number");

        // Act
        Integer result = solrService.getInteger(doc, "testField");

        // Assert
        assertNull(result);
    }

    @Test
    void testGetInteger_WithNullValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", null);

        // Act
        Integer result = solrService.getInteger(doc, "testField");

        // Assert
        assertNull(result);
    }

    @Test
    void testGetInteger_WithNonExistentField() {
        // Arrange
        SolrDocument doc = new SolrDocument();

        // Act
        Integer result = solrService.getInteger(doc, "nonExistentField");

        // Assert
        assertNull(result);
    }

    @Test
    void testGetInteger_WithDoubleValue() {
        // Arrange
        SolrDocument doc = new SolrDocument();
        doc.setField("testField", 42.5);

        // Act
        Integer result = solrService.getInteger(doc, "testField");

        // Assert
        assertNull(result); // Double is not handled, should return null
    }

    @Test
    void testConfigurationValues() {
        // Test that configuration values are properly set
        assertEquals("localhost:2181", ReflectionTestUtils.getField(solrService, "zookeeperHosts"));
        assertEquals("testuser", ReflectionTestUtils.getField(solrService, "username"));
        assertEquals("testpass", ReflectionTestUtils.getField(solrService, "password"));
        assertEquals(5000, ReflectionTestUtils.getField(solrService, "connectionTimeout"));
        assertEquals(30000, ReflectionTestUtils.getField(solrService, "socketTimeout"));
    }

    @Test
    void testInit_WithDefaultConfiguration() {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);

        // Act & Assert
        assertDoesNotThrow(() -> {
            testService.init();
        });

        // Verify that solrClient is initialized
        SolrClient client = testService.getSolrClient();
        assertNotNull(client);
    }

    @Test
    void testInit_WithMultipleZookeeperHosts() {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "host1:2181,host2:2181,host3:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);

        // Act & Assert
        assertDoesNotThrow(() -> {
            testService.init();
        });

        // Verify that solrClient is initialized
        SolrClient client = testService.getSolrClient();
        assertNotNull(client);
    }

    @Test
    void testInit_WithInvalidZookeeperHosts() {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "invalid-host");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 1000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 1000);

        // Act & Assert - This should not throw during init, but may fail during actual Solr operations
        assertDoesNotThrow(() -> {
            testService.init();
        });

        // Client should still be created even with invalid hosts
        SolrClient client = testService.getSolrClient();
        assertNotNull(client);
    }

    @Test
    void testClose_WithValidClient() throws IOException {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);
        
        testService.init();
        
        // Act & Assert
        assertDoesNotThrow(() -> {
            testService.close();
        });
    }

    @Test
    void testClose_WithNullClient() {
        // Arrange
        SolrService testService = new SolrService();
        // Don't initialize, so client remains null

        // Act & Assert
        assertDoesNotThrow(() -> {
            testService.close();
        });
    }

    @Test
    void testReset_Success() throws IOException {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);
        
        testService.init();
        @SuppressWarnings("unused")
		SolrClient originalClient = testService.getSolrClient();

        // Act
        assertDoesNotThrow(() -> {
            testService.reset();
        });

        // Assert
        SolrClient newClient = testService.getSolrClient();
        assertNotNull(newClient);
        // Note: We can't easily test that it's a different instance without more complex mocking
    }

    @Test
    void testGetSolrClient_BeforeInit() {
        // Arrange
        SolrService testService = new SolrService();
        
        // Act
        SolrClient client = testService.getSolrClient();
        
        // Assert
        assertNull(client); // Should be null before init is called
    }

    @Test
    void testGetSolrClient_AfterInit() {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);
        
        testService.init();

        // Act
        SolrClient client = testService.getSolrClient();
        
        // Assert
        assertNotNull(client);
    }

    @Test
    void testSynchronizedAccess() throws InterruptedException {
        // Arrange
        SolrService testService = new SolrService();
        ReflectionTestUtils.setField(testService, "zookeeperHosts", "localhost:2181");
        ReflectionTestUtils.setField(testService, "connectionTimeout", 10000);
        ReflectionTestUtils.setField(testService, "socketTimeout", 60000);
        
        testService.init();

        // Act - Test concurrent access to getSolrClient
        Thread[] threads = new Thread[10];
        SolrClient[] clients = new SolrClient[10];

        for (int i = 0; i < 10; i++) {
            final int index = i;
            threads[i] = new Thread(() -> {
                clients[index] = testService.getSolrClient();
            });
            threads[i].start();
        }

        // Wait for all threads to complete
        for (Thread thread : threads) {
            thread.join();
        }

        // Assert - All threads should get the same client instance
        for (int i = 0; i < 10; i++) {
            assertNotNull(clients[i]);
            assertSame(clients[0], clients[i]); // Same instance
        }
    }
}