/**
 * 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 java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.softcorporation.sandi.base.service.ConfigurationService;
import com.softcorporation.sandi.base.util.ConfigurationException;
import com.softcorporation.sandi.base.util.Utils;

@Service
public class SolrConfigurationService implements ConfigurationService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SolrConfigurationService.class);

    /**
     * Collections directory
     */
    @Value("${sandi.collections.directory:/sandi/conf/collections}")
    private String collectionsDirectory;
    
    @Autowired
    private SolrService solrService;
    
    @Override
    public boolean hasConfiguration(String name) throws ConfigurationException {
    	List<String> configurations = listConfigurations();
    	if (configurations.contains(name)) {
    		return true;
    	}
    	return false;
    }
    
    @Override
    public List<String> listConfigurations() throws ConfigurationException {
        LOGGER.debug("Listing all configuration sets from Solr ZooKeeper");
        
        try {
            ConfigSetAdminRequest.List listRequest = new ConfigSetAdminRequest.List();
            org.apache.solr.client.solrj.response.ConfigSetAdminResponse response = listRequest.process(solrService.getSolrClient());
            
            @SuppressWarnings("unchecked")
            List<String> configSets = (List<String>) response.getResponse().get("configSets");
            if (configSets == null) {
                configSets = new java.util.ArrayList<>();
            }
            
            LOGGER.info("Found {} configuration sets: {}", configSets.size(), configSets);
            
            return configSets;
            
        } catch (SolrServerException e) {
            LOGGER.error("Failed to list configuration sets: {}", e.getMessage(), e);
            solrService.reset();
            throw new ConfigurationException("Failed to list configuration sets: " + e.getMessage());
        } catch (IOException e) {
            LOGGER.error("Failed to list configuration sets: {}", e.getMessage(), e);
            throw new ConfigurationException("Failed to list configuration sets: " + e.getMessage());
		}
    }

    @Override
    public void uploadConfiguration(String name) throws ConfigurationException {
		uploadConfiguration(name, Path.of(collectionsDirectory, name));
    }
    
    @Override
    public void uploadConfiguration(String name, Path path) throws ConfigurationException {
        if (name == null || name.trim().isEmpty()) {
            throw new ConfigurationException("Configuration set name cannot be null or empty");
        }
        
        if (path == null || !Files.exists(path)) {
            throw new ConfigurationException("Configuration set path must exist: " + path);
        }

        LOGGER.info("Uploading configuration set '{}' from path: {}", name, path);
        
        Path tempZip = null;
        try {
            tempZip = Files.createTempFile("configfile-", ".zip");
            Utils.createZipFile(path, tempZip);
            
            ConfigSetAdminRequest.Upload uploadRequest = new ConfigSetAdminRequest.Upload();
            uploadRequest.setConfigSetName(name);
            uploadRequest.setUploadFile(tempZip.toFile(), "application/zip");
            uploadRequest.process(solrService.getSolrClient());
            
            LOGGER.info("Successfully uploaded configuration set '{}' to ZooKeeper", name);
            
        } catch (SolrServerException | IOException e) {
            LOGGER.error("Failed to upload configuration set '{}': {}", name, e.getMessage());
            throw new ConfigurationException("Failed to upload configuration set: " + e.getMessage());
        } finally {
        	if (tempZip != null) {
                try {
					Files.deleteIfExists(tempZip);
				} catch (IOException e) {
		            LOGGER.warn("Failed to remove tmp file '{}': {}", tempZip.toString(), e.getMessage());
				}
            }
        }
    }
    
    @Override
    public boolean deleteConfiguration(String name) throws ConfigurationException {
        if (name == null || name.trim().isEmpty()) {
            throw new ConfigurationException("Configuration set name cannot be null or empty");
        }
        
        if (!hasConfiguration(name)) {
            LOGGER.warn("Configuration set {} does not exist.");
        	return false;
        }
        
        LOGGER.info("Deleting configuration set '{}'", name);
        
        try {
            ConfigSetAdminRequest.Delete deleteRequest = new ConfigSetAdminRequest.Delete();
            deleteRequest.setConfigSetName(name);
            deleteRequest.process(solrService.getSolrClient());
            
            LOGGER.info("Successfully deleted configuration set '{}'", name);
            return true;
        } catch (SolrServerException | IOException e) {
            LOGGER.error("Failed to delete configuration set '{}': {}", name, e.getMessage(), e);
            throw new ConfigurationException("Failed to delete configuration set: " + e.getMessage());
        }
    }

    @Override
    public void uploadConfigFile(String name, Path path) throws ConfigurationException {
        if (name == null || name.trim().isEmpty()) {
            throw new ConfigurationException("Configuration set name cannot be null or empty");
        }
        
        if (path == null || !Files.exists(path)) {
            throw new ConfigurationException("Configuration path must exist: " + path);
        }
        
        if (Files.isDirectory(path)) {
            throw new ConfigurationException("Configuration must be a file: " + path);
        }
        
        LOGGER.info("Uploading configuration set '{}' from path: {}", name, path);
        
        try {
            ConfigSetAdminRequest.Upload uploadRequest = new ConfigSetAdminRequest.Upload();
            uploadRequest.setConfigSetName(name);
            uploadRequest.setUploadFile(path.toFile(), "application/zip");
            uploadRequest.process(solrService.getSolrClient());
            
            LOGGER.info("Successfully uploaded configuration set '{}' to ZooKeeper", name);
            
        } catch (SolrServerException | IOException e) {
            LOGGER.error("Failed to upload configuration set '{}': {}", name, e.getMessage(), e);
            throw new ConfigurationException("Failed to upload configuration set: " + e.getMessage());
        }
    }

    @Override
    public void deleteConfigFile(String name) throws ConfigurationException {
        LOGGER.warn("deleteConfigFile operation is not supported - individual files cannot be deleted from config sets. " +
                   "Use deleteConfigSet('{}') to delete the entire configuration set instead.", name);
        throw new ConfigurationException("Individual config file deletion is not supported. Use deleteConfigSet() instead.");
    }
    
//    @Override
    public String getCollectionsDirectory() {
    	return collectionsDirectory;
    }
    
}
