package eu.eudat.logic.utilities.documents.xml;

import eu.eudat.logic.services.forms.VisibilityRuleService;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import eu.eudat.models.data.user.components.datasetprofile.Field;
import eu.eudat.models.data.user.components.datasetprofile.FieldSet;
import eu.eudat.models.data.user.components.datasetprofile.Section;
import eu.eudat.models.data.user.composite.DatasetProfilePage;
import eu.eudat.models.data.user.composite.PagedDatasetProfile;
import org.json.JSONArray;
import org.json.JSONException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

public class ExportXmlBuilder {

    public File build(PagedDatasetProfile pagedDatasetProfile, UUID datasetProfileId, VisibilityRuleService visibilityRuleService) throws IOException {

        File xmlFile = new File(UUID.randomUUID() + ".xml");
        BufferedWriter writer = new BufferedWriter(new FileWriter(xmlFile, true));
        Document xmlDoc = XmlBuilder.getDocument();
        Element root = xmlDoc.createElement("root");
        Element datasetProfile = xmlDoc.createElement("datasetProfileId");
        datasetProfile.setTextContent(datasetProfileId.toString());
        root.appendChild(datasetProfile);
        root.appendChild(createPages(pagedDatasetProfile.getPages(), visibilityRuleService, xmlDoc));
        xmlDoc.appendChild(root);
        String xml = XmlBuilder.generateXml(xmlDoc);
        writer.write(xml);
        writer.close();
        return xmlFile;
    }

    public Element createPages(List<DatasetProfilePage> datasetProfilePages, VisibilityRuleService visibilityRuleService, Document element) {
        Element pages = element.createElement("pages");
        datasetProfilePages.forEach(item -> {
            Element page = element.createElement("page");
            page.appendChild(createSections(item.getSections(), visibilityRuleService, element));
            pages.appendChild(page);
        });
        return pages;
    }

    private Element createSections(List<Section> sections, VisibilityRuleService visibilityRuleService, Document element) {
        Element elementSections = element.createElement("sections");
        sections.forEach(section -> {
            Element elementSection = element.createElement("section");
            if (visibilityRuleService.isElementVisible(section.getId())) {
                elementSection.appendChild(createSections(section.getSections(), visibilityRuleService, element));
                elementSection.appendChild(createCompositeFields(section.getCompositeFields(), visibilityRuleService, element));
                elementSections.appendChild(elementSection);
            }
        });
        return elementSections;
    }

    private Element createCompositeFields(List<FieldSet> compositeFields, VisibilityRuleService visibilityRuleService, Document element) {
        Element elementComposites = element.createElement("composite-fields");
        compositeFields.forEach(compositeField -> {
            if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) {
                Element composite = element.createElement("composite-field");
                composite.setAttribute("id", compositeField.getId());
                if (compositeField.getTitle() != null && !compositeField.getTitle().isEmpty()) {
                    Element title = element.createElement("title");
                    title.setTextContent(compositeField.getTitle());
                    composite.appendChild(title);
                }
                if (compositeField.getDescription() != null && !compositeField.getDescription().isEmpty()) {
                    Element title = element.createElement("description");
                    title.setTextContent(compositeField.getDescription());
                    composite.appendChild(title);
                }
                composite.appendChild(createFields(compositeField.getFields(), visibilityRuleService, element));
                elementComposites.appendChild(composite);

            }
        });
        return elementComposites;
    }

    private Element createFields(List<Field> fields, VisibilityRuleService visibilityRuleService, Document element) {
        Element elementFields = element.createElement("fields");
        fields.forEach(field -> {
            if (visibilityRuleService.isElementVisible(field.getId())) {
                Element elementField = element.createElement("field");
                elementField.setAttribute("id", field.getId());
                if (field.getValue() != null) {
                    Element valueField = element.createElement("value");
                    try {
                        JSONArray jsonArray = new JSONArray(field.getValue().toString());
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < jsonArray.length(); i++) {
                            sb.append(jsonArray.getJSONObject(i).get("label").toString());
                            if (i != jsonArray.length() - 1) sb.append(", ");
                        }
                        valueField.setTextContent(sb.toString());
                    } catch (JSONException ex) {
                        valueField.setTextContent(field.getValue().toString());
                    }
                    elementField.appendChild(valueField);
                }
                elementFields.appendChild(elementField);
            }
        });
        return elementFields;
    }

    private boolean hasVisibleFields(FieldSet compositeFields, VisibilityRuleService visibilityRuleService) {
        return compositeFields.getFields().stream().anyMatch(field -> visibilityRuleService.isElementVisible(field.getId()));
    }
}
