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

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.json.JSONObject;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.softcorporation.sandi.base.model.Client;
import com.softcorporation.sandi.base.util.Constants;
import com.softcorporation.sandi.index.util.IndexerException;
import com.softcorporation.util.StringUtil;

@Service
public class ParsingService {

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

    public JSONObject parseTextFile(Client client, File file) throws IndexerException {
        LOGGER.debug("Client {} Parsing file: {}", client.getClientId(), file);
        
        JSONObject jsonDocument = new JSONObject();
        try (InputStream inputStream = new FileInputStream(file)) {
            Parser parser = new AutoDetectParser();
            BodyContentHandler handler = new BodyContentHandler(-1);
            Metadata metadata = new Metadata();
            ParseContext parseContext = new ParseContext();
            
            parser.parse(inputStream, handler, metadata, parseContext);
                    
            jsonDocument.put(Constants.URI_FIELD, file.toURI().toString());
            jsonDocument.put(Constants.FILENAME_FIELD, file.getAbsolutePath().toString());
            String content = handler.toString();
            content = StringUtil.cleanSpaces(content);
            jsonDocument.put(Constants.CONTENT_FIELD, content);
            
            for (String name : metadata.names()) {
            	if (!name.startsWith("X-TIKA")) {
                    String[] values = metadata.getValues(name);
                    if (values.length == 1) {
                    	jsonDocument.put(name, values[0]);
                    } else if (values.length > 1) {
                    	jsonDocument.put(name, values);
                    }
                }
            }
            LOGGER.debug("Client {} Successfully parsed file: {}", client.getClientId(), file);
            
        } catch (TikaException e) {
            throw new IndexerException("Tika parsing error for file: " + file, e);
        } catch (SAXException e) {
            throw new IndexerException("XML parsing error for file: " + file, e);
        } catch (Exception e) {
            throw new IndexerException("Error parsing file: " + file, e);
        }
        return jsonDocument;
    }

    public List<JSONObject> parseXmlSitemap(File file) throws IndexerException {
        List<JSONObject> entries = new ArrayList<>();
        
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();
            
            DefaultHandler handler = new DefaultHandler() {
            	
            	JSONObject entry = null;
                private boolean inLoc = false;
                private StringBuilder locContent = new StringBuilder();
                private boolean inLm = false;
                private StringBuilder lmContent = new StringBuilder();
                
                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) {
                    if ("url".equalsIgnoreCase(qName)) {
                    	entry = new JSONObject();
                    } else if ("loc".equalsIgnoreCase(qName)) {
                        inLoc = true;
                        locContent.setLength(0);
                    } else if ("lastmod".equalsIgnoreCase(qName)) {
                        inLm = true;
                        lmContent.setLength(0);
                    }
                }
                
                @Override
                public void characters(char[] ch, int start, int length) {
                    if (inLoc) {
                        locContent.append(ch, start, length);
                    } else if (inLm) {
                        lmContent.append(ch, start, length);
                    }
                }
                
                @Override
                public void endElement(String uri, String localName, String qName) {
                    if ("url".equalsIgnoreCase(qName)) {
                    	if (entry != null) {
                            entries.add(entry);
                    	}
                    	entry = null;
                    } if ("loc".equalsIgnoreCase(qName)) {
                        inLoc = false;
                        String url = locContent.toString().trim();
                        if (!url.isEmpty()) {
                            entry.put("url", url);
                        }
                    } else  if ("lastmod".equalsIgnoreCase(qName)) {
                        inLm = false;
                        String date = lmContent.toString().trim();
                        if (!date.isEmpty()) {
                            entry.put("lastmod", date);
                        }
                    }
                }
            };
            
            try (InputStream inputStream = new FileInputStream(file)) {
                saxParser.parse(inputStream, handler);
            }
            
        } catch (Exception e) {
            throw new IndexerException("Error parsing sitemap XML", e);
        }
        
        return entries;
    }

}