package org.texttechnologylab.project.gruppe_05_1.xml.speeches;

import org.texttechnologylab.project.gruppe_05_1.util.Logger;
import org.texttechnologylab.project.gruppe_05_1.util.PPRUtils;
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.*;
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.AgendaItem;
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Session;
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class SpeechParser {

    private List<Speech> speeches;
    private List<AgendaItem> agendaItems;

    public List<Speech> getSpeeches() {
        return speeches;
    }

    public List<AgendaItem> getAgendaItems() {
        return agendaItems;
    }

    public void setParseLegislativePeriods(Boolean parseLegislativePeriods) {
    }

    public List<Session> parseAllSessions() {
        List<Session> sessions = new ArrayList<>();
        this.speeches = new ArrayList<>();
        this.agendaItems = new ArrayList<>();
        Set<Document> xmlDocuments = PPRUtils.processXML();
        Logger.info("All sessions parsed");
        for (org.w3c.dom.Document xmlDoc : xmlDocuments) {
            try {
                File tempFile = convertDocumentToFile(xmlDoc);
                Session session = parseSessionFile(tempFile);
                sessions.add(session);
                tempFile.delete();  // Lösche die temporäre Datei nach der Verarbeitung
            } catch (Exception e) {
                Logger.error("Error parsing XML document.");
                Logger.error(e.getMessage());
            }
        }
        return sessions;

    }

    public List<Session> parseAllSessions(Set<Document> xmlDocuments) {
        List<Session> sessions = new ArrayList<>();
        this.speeches = new ArrayList<>();
        this.agendaItems = new ArrayList<>();
        Logger.info("All new sessions parsed");
        for (org.w3c.dom.Document xmlDoc : xmlDocuments) {
            try {
                File tempFile = convertDocumentToFile(xmlDoc);
                Session session = parseSessionFile(tempFile);
                sessions.add(session);
                tempFile.delete();  // Lösche die temporäre Datei nach der Verarbeitung
            } catch (Exception e) {
                Logger.error("Error parsing XML document.");
                Logger.error(e.getMessage());
            }
        }
        return sessions;

    }

    private Session parseSessionFile(File file) throws Exception {
        //file = removeDoctypeAnnotation(file.getAbsolutePath());

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(file);

        // Extract session details
        Element root = document.getDocumentElement();
        String legislativePeriod = root.getAttribute("wahlperiode");
        int sessionId = Integer.parseInt(root.getAttribute("sitzung-nr"));
        String sessionDate = root.getAttribute("sitzung-datum");
        Element startTimeElement = (Element) root.getElementsByTagName("sitzungsbeginn").item(0);
        String startTimeString = startTimeElement != null ? startTimeElement.getAttribute("sitzung-start-uhrzeit") : null;

        String startTime = startTimeString != null ? sessionDate + " " + startTimeString : sessionDate;

        Element sessionEndElement = (Element) root.getElementsByTagName("sitzungsende").item(0);
        String sessionEndTime = sessionEndElement != null ? sessionEndElement.getAttribute("sitzung-ende-uhrzeit") : null;

        Session_File_Impl session = new Session_File_Impl(legislativePeriod, sessionId, startTime, sessionEndTime);

        // Parse agenda items
        NodeList agendaNodes = document.getElementsByTagName("tagesordnungspunkt");
        for (int agendaItemId = 0; agendaItemId < agendaNodes.getLength(); agendaItemId++) {
            Element agendaElement = (Element) agendaNodes.item(agendaItemId);
            if (agendaElement == null) continue;

            String agendaTitle = agendaElement.getAttribute("top-id");

            AgendaItem_File_Impl agendaItemFileImpl = new AgendaItem_File_Impl(agendaItemId, sessionId, agendaTitle);

            this.agendaItems.add(agendaItemFileImpl);

            // Parse speeches
            NodeList speechNodes = agendaElement.getElementsByTagName("rede");
            for (int speechId = 0; speechId < speechNodes.getLength(); speechId++) {
                Element speechElement = (Element) speechNodes.item(speechId);
                if (speechElement == null) continue;

                // Parse speaker
                Element speakerElement = (Element) speechElement.getElementsByTagName("redner").item(0);
                if (speakerElement == null) continue;

                int speakerId = Integer.parseInt(speakerElement.getAttribute("id"));
                Element nameElement = (Element) speakerElement.getElementsByTagName("name").item(0);
                if (nameElement == null) continue;
                String redeID = speechElement.getAttribute("id");
                String title = getOptionalTextContent(nameElement, "titel");
                String firstName = getOptionalTextContent(nameElement, "vorname");
                String lastName = getOptionalTextContent(nameElement, "nachname");
                String fraction = getOptionalTextContent(nameElement, "fraktion");

                String speakerName = (title != null ? title + " " : "") + firstName + " " + lastName;
                Speech_File_Impl speech = new Speech_File_Impl(sessionId, agendaItemId, speechId, speakerId, speakerName, fraction, redeID);

                // Add the speaker to speech contents
                speech.addContent(new Speaker_File_Impl(0, speechId, speakerId, speakerName, fraction));

                // Parse content in order
                NodeList contentNodes = speechElement.getChildNodes();
                for (int k = 0; k < contentNodes.getLength(); k++) {
                    Node contentNode = contentNodes.item(k);
                    if (contentNode == null || contentNode.getNodeType() != Node.ELEMENT_NODE) continue;

                    Element contentElement = (Element) contentNode;
                    String tagName = contentElement.getTagName();

                    switch (tagName) {
                        case "p":
                            String paragraphClass = contentElement.getAttribute("klasse");
                            if ("redner".equals(paragraphClass)) {
                                // This case can be skipped as the speaker is already added
                                continue;
                            } else if ("kommentar".equals(paragraphClass)) {
                                String comment = contentElement.getTextContent().trim();
                                String commentatorName = ""; // Extract if present
                                speech.addContent(new Comment_File_Impl(k + 1, speechId, commentatorName, comment));
                            } else {
                                String line = contentElement.getTextContent().trim();
                                speech.addContent(new Line_File_Impl(k + 1, speechId, line));
                            }
                            break;

                        case "kommentar":
                            String comment = contentElement.getTextContent().trim();
                            String commentatorName = ""; // Extract if available
                            speech.addContent(new Comment_File_Impl(k + 1, speechId, commentatorName, comment));
                            break;

                        default:
                            break;
                    }
                }

                agendaItemFileImpl.addSpeech(speech);
                this.speeches.add(speech);
            }

            session.addAgendaItem(agendaItemFileImpl);
        }
        return session;
    }

    private static String getOptionalTextContent(Element parent, String tagName) {
        NodeList nodes = parent.getElementsByTagName(tagName);
        if (nodes.getLength() > 0) {
            Node node = nodes.item(0);
            if (node != null) {
                return node.getTextContent().trim();
            }
        }
        return null;
    }

    /**
     * Konvertiert ein org.w3c.dom.Document in eine temporäre Datei.
     */
    private File convertDocumentToFile(org.w3c.dom.Document xmlDoc) throws Exception {
        File tempFile = File.createTempFile("session_", ".xml");
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");

        DOMSource source = new DOMSource(xmlDoc);
        StreamResult result = new StreamResult(tempFile);
        transformer.transform(source, result);

        return tempFile;
    }

}
