/**
 * 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;

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

import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.softcorporation.sandi.base.model.Client;
import com.softcorporation.sandi.base.util.ClientException;
import com.softcorporation.sandi.base.util.CollectionException;

/**
 * Unit tests for ClientService interface
 * Note: These tests use a mock implementation since ClientService is an interface
 */
@ExtendWith(MockitoExtension.class)
class ClientServiceTest {

    @Mock
    private ClientService clientService;

    private Client testClient;

    @BeforeEach
    void setUp() {
        testClient = new Client();
        testClient.setClientId("test-client-id");
        testClient.setName("Test Client");
        testClient.setCollection("test-collection");
        testClient.setActive(true);
        testClient.setLegacy(false);
        testClient.setFieldsHigh("title");
        testClient.setFieldsLow("keywords,summary");
        testClient.setFieldsContent("content");
    }

    @Test
    void testGetClient_Success() throws ClientException {
        // Arrange
        when(clientService.getClient("test-client-id")).thenReturn(testClient);

        // Act
        Client result = clientService.getClient("test-client-id");

        // Assert
        assertNotNull(result);
        assertEquals("test-client-id", result.getClientId());
        assertEquals("Test Client", result.getName());
        assertEquals("test-collection", result.getCollection());
        assertTrue(result.isActive());
        assertFalse(result.isLegacy());

        verify(clientService).getClient("test-client-id");
    }

    @Test
    void testGetClient_NotFound() throws ClientException {
        // Arrange
        when(clientService.getClient("non-existent-client")).thenReturn(null);

        // Act
        Client result = clientService.getClient("non-existent-client");

        // Assert
        assertNull(result);
        verify(clientService).getClient("non-existent-client");
    }

    @Test
    void testGetClient_ThrowsException() throws ClientException {
        // Arrange
        when(clientService.getClient("error-client")).thenThrow(new ClientException("Client service error"));

        // Act & Assert
        ClientException exception = assertThrows(ClientException.class, () -> {
            clientService.getClient("error-client");
        });

        assertEquals("Client service error", exception.getMessage());
        verify(clientService).getClient("error-client");
    }

    @Test
    void testListClients_Success() throws ClientException {
        // Arrange
        Client client1 = new Client();
        client1.setClientId("client1");
        client1.setName("Client One");

        Client client2 = new Client();
        client2.setClientId("client2");
        client2.setName("Client Two");

        List<Client> expectedClients = Arrays.asList(client1, client2);
        when(clientService.listClients()).thenReturn(expectedClients);

        // Act
        List<Client> result = clientService.listClients();

        // Assert
        assertNotNull(result);
        assertEquals(2, result.size());
        assertEquals("client1", result.get(0).getClientId());
        assertEquals("client2", result.get(1).getClientId());

        verify(clientService).listClients();
    }

    @Test
    void testListClients_Empty() throws ClientException {
        // Arrange
        when(clientService.listClients()).thenReturn(Arrays.asList());

        // Act
        List<Client> result = clientService.listClients();

        // Assert
        assertNotNull(result);
        assertTrue(result.isEmpty());

        verify(clientService).listClients();
    }

    @Test
    void testSaveClient_Success() throws ClientException {
        // Arrange
        doNothing().when(clientService).saveClient(testClient);

        // Act & Assert
        assertDoesNotThrow(() -> {
            clientService.saveClient(testClient);
        });

        verify(clientService).saveClient(testClient);
    }

    @Test
    void testSaveClient_WithConfiguration() throws ClientException, CollectionException {
        // Arrange
        String configuration = "test-configuration";
        doNothing().when(clientService).saveClient(testClient, configuration);

        // Act & Assert
        assertDoesNotThrow(() -> {
            clientService.saveClient(testClient, configuration);
        });

        verify(clientService).saveClient(testClient, configuration);
    }

    @Test
    void testSaveClient_ThrowsClientException() throws ClientException {
        // Arrange
        doThrow(new ClientException("Save failed")).when(clientService).saveClient(testClient);

        // Act & Assert
        ClientException exception = assertThrows(ClientException.class, () -> {
            clientService.saveClient(testClient);
        });

        assertEquals("Save failed", exception.getMessage());
        verify(clientService).saveClient(testClient);
    }

    @Test
    void testSaveClient_ThrowsCollectionException() throws ClientException, CollectionException {
        // Arrange
        String configuration = "invalid-configuration";
        doThrow(new CollectionException("Collection creation failed"))
            .when(clientService).saveClient(testClient, configuration);

        // Act & Assert
        CollectionException exception = assertThrows(CollectionException.class, () -> {
            clientService.saveClient(testClient, configuration);
        });

        assertEquals("Collection creation failed", exception.getMessage());
        verify(clientService).saveClient(testClient, configuration);
    }

    @Test
    void testDeleteClient_Success() throws ClientException {
        // Arrange
        when(clientService.deleteClient("test-client-id")).thenReturn(true);

        // Act
        boolean result = clientService.deleteClient("test-client-id");

        // Assert
        assertTrue(result);
        verify(clientService).deleteClient("test-client-id");
    }

    @Test
    void testDeleteClient_NotFound() throws ClientException {
        // Arrange
        when(clientService.deleteClient("non-existent-client")).thenReturn(false);

        // Act
        boolean result = clientService.deleteClient("non-existent-client");

        // Assert
        assertFalse(result);
        verify(clientService).deleteClient("non-existent-client");
    }

    @Test
    void testDeleteClient_ThrowsException() throws ClientException {
        // Arrange
        when(clientService.deleteClient("error-client")).thenThrow(new ClientException("Delete failed"));

        // Act & Assert
        ClientException exception = assertThrows(ClientException.class, () -> {
            clientService.deleteClient("error-client");
        });

        assertEquals("Delete failed", exception.getMessage());
        verify(clientService).deleteClient("error-client");
    }

    @Test
    void testInit() {
        // Arrange
        doNothing().when(clientService).init();

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

        verify(clientService).init();
    }

    @Test
    void testGetClient_WithNullClientId() throws ClientException {
        // Arrange
        when(clientService.getClient(null)).thenThrow(new ClientException("Client ID cannot be null"));

        // Act & Assert
        ClientException exception = assertThrows(ClientException.class, () -> {
            clientService.getClient(null);
        });

        assertEquals("Client ID cannot be null", exception.getMessage());
        verify(clientService).getClient(null);
    }

    @Test
    void testGetClient_WithEmptyClientId() throws ClientException {
        // Arrange
        when(clientService.getClient("")).thenThrow(new ClientException("Client ID cannot be empty"));

        // Act & Assert
        ClientException exception = assertThrows(ClientException.class, () -> {
            clientService.getClient("");
        });

        assertEquals("Client ID cannot be empty", exception.getMessage());
        verify(clientService).getClient("");
    }
}