/*
 * Copyright (c) 2025 Rostock University Library
 * Licensed under the MIT License. See LICENSE file in the project root.
 */
package de.uni.rostock.ub.wsrb.edition.webapp.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.transform.stream.StreamSource;

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.lang.NonNull;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;

import de.uni.rostock.ub.wsrb.edition.webapp.util.WSRBUtil;
import jakarta.annotation.PostConstruct;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XdmMap;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.s9api.Xslt30Transformer;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;

@Service
public class XSLTEditionService {

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

    @Value("${wsrb.edition.id}")
    private String editionId;

    @Value("${wsrb.folder.teixml}")
    private String teixmlFolder;

    @Value("${wsrb.folder.xslt}")
    private String xsltFolder;

    @Autowired
    DataService dataService;

    XsltExecutable xslSpruchliste;
    XsltExecutable xslSolr;
    XsltExecutable xslTaxLabels;

    Processor processor;

    Map<String, String> taxLabels = new ConcurrentHashMap<>();

    @PostConstruct
    private void init() {
        processor = new Processor(false);
        try (
            InputStream instrXsltSpruchliste = getClass().getResourceAsStream(xsltFolder + "edition/html4edition.xsl");
            InputStream instrXsltEdition = getClass().getResourceAsStream(xsltFolder + "solr/solr4edition.xsl");
            InputStream instrXsltTaxlabels = getClass().getResourceAsStream(xsltFolder + "edition/map4taxlabels.xsl")) {

            XsltCompiler compiler = processor.newXsltCompiler();
            xslSpruchliste = compiler.compile(new StreamSource(instrXsltSpruchliste));
            xslSolr = compiler.compile(new StreamSource(instrXsltEdition));
            xslTaxLabels = compiler.compile(new StreamSource(instrXsltTaxlabels));

            initTaxLabels();
        } catch (SaxonApiException | IOException e) {
            LOGGER.error("Initialization Error", e);
        }
    }

    public String createFilteredSprueche(@NonNull List<String> id, @NonNull List<String> filter,
        Map<String, String> highlightMap) {
        StringWriter sw = new StringWriter();

        try (InputStream instrEditionXml
            = getClass().getResourceAsStream(teixmlFolder + "edition/" + editionId + WSRBUtil.TEI_FILE_EXTENSION)) {
            ObjectMapper om = new ObjectMapper();
            String hightlightMapJson = om.writeValueAsString(highlightMap);

            Xslt30Transformer transformer = xslSpruchliste.load30();
            Map<QName, XdmValue> params = Map.ofEntries(
                Map.entry(new QName("id"), new XdmAtomicValue(String.join(" ", WSRBUtil.flattenParamList(id)))),
                Map.entry(new QName("filter"), new XdmAtomicValue(String.join(" ", filter))),
                Map.entry(new QName("json_search_highlight"), new XdmAtomicValue(hightlightMapJson)),
                Map.entry(new QName("map_id2line"), XdmMap.makeMap(dataService.retrieveIdToLineMap())));

            transformer.setStylesheetParameters(params);
            transformer.transform(new StreamSource(instrEditionXml), WSRBUtil.createSerializer(processor, sw));
        } catch (Exception e) {
            LOGGER.error("Error in createFilteredSprueche()", e);
        }
        return sw.toString();
    }

    public String createSolr4Edition() {
        StringWriter sw = new StringWriter();
        String path = teixmlFolder + "edition/" + editionId + WSRBUtil.TEI_FILE_EXTENSION;
        try (InputStream instrEditionXml = getClass().getResourceAsStream(path)) {
            Xslt30Transformer transformer = xslSolr.load30();
            transformer.transform(new StreamSource(instrEditionXml), WSRBUtil.createSerializer(processor, sw));
        } catch (Exception e) {
            LOGGER.error("Error in createSolr4Edition()", e);
        }
        return sw.toString();
    }

    private void initTaxLabels() throws IOException, SaxonApiException {
        String path = teixmlFolder + "edition/" + editionId + WSRBUtil.TEI_FILE_EXTENSION;
        try (InputStream instrEditionXml = getClass().getResourceAsStream(path)) {
            Xslt30Transformer transformer = xslTaxLabels.load30();
            StreamSource in = new StreamSource(instrEditionXml);
            XdmValue result = transformer.applyTemplates(in);
            if (result instanceof XdmMap xm) {
                // convert the XdmMap to a "standard" Java map
                Map<XdmAtomicValue, XdmValue> m = xm.asMap();
                for (XdmAtomicValue k : m.keySet()) {
                    if (m.get(k) instanceof XdmAtomicValue v) {
                        taxLabels.put(k.getStringValue(), v.getStringValue());
                    }
                }
            }
        }
    }

    public Map<String, String> getTaxLabels() {
        return taxLabels;
    }

}
