/**
 * 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.index.service.processors;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.softcorporation.sandi.base.model.Client;
import com.softcorporation.sandi.base.util.ClientException;
import com.softcorporation.sandi.base.util.Utils;
import com.softcorporation.sandi.index.model.IndexingJob;
import com.softcorporation.sandi.index.service.ParsingService;
import com.softcorporation.sandi.index.util.IndexerException;

@Service
public class SiteProcessingService extends JobProcessingService {

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

    @Autowired
    protected ParsingService textParsingService;

    public void executeIndexingJob(IndexingJob job) throws IndexerException {
        String jobId = job.getJobId();
        String stopJobId = getStopIndexingJobId();
    	if (stopJobId != null && jobId.equals(stopJobId)) {
    		stopIndexingJob(null);
    	}
        LOGGER.info("Starting execution of indexing job: {}", job);
    	
        try {
            // Get client
            Client client = clientService.getClient(job.getClientId());
            if (client == null) {
                throw new ClientException("Client not found: " + job.getClientId());
            }
            String clientId = client.getClientId();

            // Validate directory exists
            Path directoryPath = Paths.get(job.getLocation());
            if (!Files.exists(directoryPath) || !Files.isDirectory(directoryPath)) {
                throw new IOException("Directory does not exist or is not a directory: " + job.getLocation());
            }

            String fileExtensions = job.getFileExtensions();
            if (fileExtensions == null) {
            	fileExtensions = "htm,html,xhtml,txt,text,pdf,doc,docx,xls";
            }
            List<String> desiredExtensions = Utils.stringToList(fileExtensions, false);
            
            // Process files recursively
            int totalFiles = 0;
            int totalDocuments = 0;
            int successfulDocuments = 0;
            int failedDocuments = 0;

            try (Stream<Path> paths = Files.walk(directoryPath)) {
            	List<Path> filteredFiles = paths
                    .filter(Files::isRegularFile)
                    .filter(path -> desiredExtensions.stream().anyMatch(ext -> path.getFileName().toString().endsWith(ext)))
                    .collect(Collectors.toList());

                LOGGER.info("Found {} matching files in directory: {}", filteredFiles.size(), job.getLocation());
                job.setTotalFiles(filteredFiles.size());

                for (Path path : filteredFiles) {
                    stopJobId = getStopIndexingJobId();
                	if (stopJobId != null && jobId.equals(stopJobId)) {
                		break;
                	}
                    totalFiles++;
                    LOGGER.info("Client {} Processing file: {}", clientId, path);

                    try {
                        JSONObject jsonDocument = textParsingService.parseTextFile(client, path.toFile());
                        
                        //TODO checksum covered in processJsonDocument, where is timestamp? 
//                      document.put(Constants.CHECKSUM_FIELD, Utils.getFileChecksum(tempFile.toString()));
//                      document.put(Constants.TIMESTAMP, System.currentTimeMillis());
                        
                        indexerService.processJsonDocument(client, jsonDocument, job.getForceReindexing());
                        LOGGER.info("Client {} Successfully processed and indexed file: {}", clientId, path);

                        totalDocuments++;
                        successfulDocuments++;
                        
                        // TODO 500?
                        if (totalDocuments % 500 == 0) {
                            indexerService.commit(client.getCollection());
                        }
                        
                        // Update job progress
                        job.setTotalDocuments(totalDocuments);
                        job.setSuccessfulDocuments(successfulDocuments);
                        job.setFailedDocuments(failedDocuments);

                    } catch (Exception e) {
                    	String message = e.getMessage();
                        LOGGER.error("Error processing file {}: {}", path, message, e);
                        failedDocuments++;
                        job.setFailedDocuments(failedDocuments);
                        if (message.contains("Collection not found")) {
                            throw new IOException(message);
                        }
                    }
                }
            }
            indexerService.commit(client.getCollection());
            
            // Update final job statistics
            job.setTotalFiles(totalFiles);
            job.setTotalDocuments(totalDocuments);
            job.setSuccessfulDocuments(successfulDocuments);
            job.setFailedDocuments(failedDocuments);

            stopJobId = getStopIndexingJobId();
        	if (stopJobId != null && jobId.equals(stopJobId)) {
        		stopIndexingJob(null);
                job.setMessage(String.format("Cancelled with %d successful documents out of %d indexed", 
                		successfulDocuments, totalDocuments));
        	} else {
                if (failedDocuments > 0) {
                    job.setMessage(String.format("Completed with %d failed documents out of %d total", 
                        failedDocuments, totalDocuments));
                } else {
                    job.setMessage("All documents processed successfully");
                }
        	}
            LOGGER.info("Completed indexing job {}: {} files, {} total documents, {} successful, {} failed", 
                jobId, totalFiles, totalDocuments, successfulDocuments, failedDocuments);

        } catch (Exception e) {
        	String message = "Error executing indexing job: " + jobId + " " + e.getMessage();
            LOGGER.error(message);
            job.setMessage(message);
            throw new IndexerException(message);
        }
    }

}