package hr.com.port.ips.eracun.validation.rules;

import hr.com.port.ips.eracun.validation.BusinessRule;
import hr.com.port.ips.eracun.validation.RuleResult;
import hr.com.port.ips.eracun.validation.XmlEval;

import org.w3c.dom.*;
import org.apache.log4j.Logger;
import hr.com.port.functions.Functions;
import hr.com.port.ips.eracun.validation.Bt;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

public final class HrBr33 implements BusinessRule {
    private static final Logger logger = Logger.getLogger(HrBr33.class);

    public String getId() { return "HR-BR-33"; }
    public String getDescription() {
        return "Račun ne smije sadržavati prazne xml elemente osim elementa s elektroničkim potpisom računa.";
    }

    public RuleResult validate(Document doc) {
        try {           
			String xpathExpr = "//*[normalize-space(text())='' and not(*) and not(ancestor-or-self::*[" +
				"namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Signature-2' " +
				"or namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2' " +
				"or namespace-uri() = 'http://www.w3.org/2000/09/xmldsig#' " +
				"or namespace-uri() = 'http://uri.etsi.org/01903/v1.3.2#' ])]";
			
            XmlEval eval = new XmlEval();
            int count = eval.count(doc, xpathExpr);

            if (count == 0) {
                return new RuleResult(getId(), true, "OK");
            } else {
                // Samostalno dohvaćanje NodeList-a
                XPath xpath = XPathFactory.newInstance().newXPath();
                NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, doc, XPathConstants.NODESET);

                String firstPath = nodes.getLength() > 0 ? buildPath(nodes.item(0)) : "";
                String lastPath = nodes.getLength() > 1 ? buildPath(nodes.item(nodes.getLength() - 1)) : firstPath;

                String msg = "Postoje prazni XML elementi (osim potpisa). " +
                             "Ukupno: " + count +
                             (firstPath.isEmpty() ? "" : " | Prvi: " + firstPath) +
                             (lastPath.isEmpty() ? "" : " | Zadnji: " + lastPath);

                // Detaljno u log
                for (int i = 0; i < nodes.getLength(); i++) {
                    logger.debug("HR-BR-33 EMPTY: " + buildPath(nodes.item(i)));
                }

                return new RuleResult(getId(), false, msg);
            }
        } catch (Exception ex) {
            logger.error(new Functions().logging(ex));
            return new RuleResult(getId(), false, "Greška u provjeri: " + ex.getMessage());
        }
    }

    // Pomoćna metoda za dohvat “btpath”-like putanje
    private String buildPath(Node node) {
        StringBuilder path = new StringBuilder();
        while (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
            String name = (node.getPrefix() != null ? node.getPrefix() + ":" : "") + node.getLocalName();
            Node parent = node.getParentNode();

            // Izračunaj index među braćom istog imena
            int index = 1;
            if (parent != null) {
                NodeList siblings = parent.getChildNodes();
                for (int i = 0; i < siblings.getLength(); i++) {
                    Node sib = siblings.item(i);
                    if (sib.getNodeType() == Node.ELEMENT_NODE &&
                        sib.getLocalName().equals(node.getLocalName()) &&
                        ((sib.getPrefix() == null && node.getPrefix() == null) ||
                         (sib.getPrefix() != null && sib.getPrefix().equals(node.getPrefix())))) {
                        if (sib == node) break;
                        index++;
                    }
                }
            }
            path.insert(0, "/" + name + "[" + index + "]");
            node = parent;
            if (node != null && node.getNodeType() == Node.DOCUMENT_NODE) break;
        }
        return path.toString();
    }
}