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

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.Constants;
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 SitemapProcessingService extends JobProcessingService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SitemapProcessingService.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();

            Path tmpDirPath = Utils.getTempDir();
            File sitemap = tmpDirPath.resolve("sitemap_" + System.currentTimeMillis() + ".xml").toFile();

            String url = job.getLocation();
            long length = Utils.get(url, sitemap);
            if (length <= 0) {
                throw new IOException("Sitemap does not exist at url: " + url);
            }
            LOGGER.info("Downloaded {} bytes sitemap: {}", length, url);

//            String fileExtensions = "htm,html,xhtml,txt,text,pdf,doc,docx,xls";
//            List<String> desiredExtensions = Utils.stringToList(fileExtensions);
            
            // Process sitemap
            int totalDocuments = 0;
            int successfulDocuments = 0;
            int failedDocuments = 0;
            try {
                List<JSONObject> jsonLinks = textParsingService.parseXmlSitemap(sitemap);
                LOGGER.debug("Found {} URLs in sitemap: {}", jsonLinks.size(), url);

                for (JSONObject jsonLink : jsonLinks) {
                    stopJobId = getStopIndexingJobId();
                    if (stopJobId != null && jobId.equals(stopJobId)) {
                        LOGGER.info("Job {} was stopped during sitemap processing", jobId);
                        break;
                    }
                    
                    try {
                        processDocument(client, jsonLink, tmpDirPath);
                        LOGGER.debug("Client {} Successfully processed document: {}", clientId, jsonLink);
                    } catch (Exception e) {
                        LOGGER.error("Client {} Error processing document from URL {}: {}", clientId, jsonLink, e.getMessage(), e);
                        throw e;
                    }
                }
            } finally {
               	sitemap.delete();
            }

            indexerService.commit(client.getCollection());
            
            // Update final job statistics
            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 {}: {} total documents, {} successful, {} failed", 
                jobId, 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);
        }
    }

    private void processDocument(Client client, JSONObject jsonDocument, Path tmpDirPath)
    		throws IndexerException {
    	String documentUrl = jsonDocument.getString("url");
    	LOGGER.debug("Client {} Processing document from URL: {}", client.getClientId(), documentUrl);
        
        File file = tmpDirPath.resolve("document_" + System.currentTimeMillis()).toFile();
        
        try {
        	long length = Utils.get(documentUrl, file);
        	if (length > 0) {
                JSONObject document = textParsingService.parseTextFile(client, file);
                
                document.put(Constants.URL_FIELD, documentUrl);
                document.put(Constants.FILENAME_FIELD, file.getAbsolutePath());

                //TODO checksum covered in processJsonDocument, where is timestamp? 
//              document.put(Constants.CHECKSUM_FIELD, Utils.getFileChecksum(tempFile.toString()));
//              document.put(Constants.TIMESTAMP, System.currentTimeMillis());
                
                indexerService.indexDocument(client.getCollection(), document);
        	} else {
                LOGGER.error("Client {} Cannot download document from url: {}", client.getClientId(), documentUrl);
        	}
        } catch (IOException e) {
            LOGGER.error("Client {} Exception processing document from url: {}", client.getClientId(), documentUrl);
		} finally {
        	file.delete();        	
        }
    }

}