package de.thpeetz.kontor.data.views;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.html.H4;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import de.thpeetz.kontor.data.services.DataManagementService;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.parser.ParseException;

import java.io.*;
import java.util.*;

@Slf4j
public class ImportArea extends VerticalLayout {

    protected File uploadFolder;
    DataManagementService service;
    boolean pruneTables = false;

    public ImportArea(File uploadFolder, Checkbox pruneTablesCheckbox, DataManagementService service) {
        this.uploadFolder = uploadFolder;
        this.service = service;
        this.pruneTables = pruneTablesCheckbox.isEnabled();
        setMargin(true);
    }

    public void processFiles() {
        removeAll();
        if (pruneTables) {
            add(new Paragraph("prune all tables"));
        }
        add(new H4("Process file"));

        for (File file: uploadFolder.listFiles()) {
            add(new Paragraph("reading " + file.getName()));
            try {
                processFile(file);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void processFile(File file) throws FileNotFoundException, IOException, ParseException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode node = objectMapper.readTree(file);
        log.info("parsing: {}, {}", node.getNodeType(), node.size());
        Iterator<String> fieldNamesIterator = node.fieldNames();
        while (fieldNamesIterator.hasNext()) {
            String fieldName = fieldNamesIterator.next();
            parseRoot(node, fieldName);
        }
    }

    private void parseRoot(JsonNode parentNode, String field) {
        JsonNode node = parentNode.get(field);
        String nodeType = String.valueOf(node.getNodeType());
        if (nodeType.equals("ARRAY")) {
            log.info("  {}: {}", field, node.size());
            Iterator<JsonNode> elements = node.elements();
            while (elements.hasNext()) {
                JsonNode subNode = elements.next();
                String status = parseNode(subNode, field);
                add(new Paragraph(status));
            }
        } else {
            log.info("unknown type: {}", nodeType);
        }
    }

    private String parseNode(JsonNode node, String nodeName) {
        Map<String, String> fields = parseFields(node);
        return service.getEntry(nodeName, fields);
    }

    private Map<String, String> parseFields(JsonNode node) {
        Map<String, String> fields = new HashMap<>();
        node.fieldNames().forEachRemaining(field -> {

            JsonNode value = node.get(field);
            log.debug("type: {}", value.getNodeType());
            JsonNodeType nodeType = value.getNodeType();
            switch (nodeType) {
                case NUMBER:
                    fields.put(field, String.valueOf(value.intValue()));
                    break;
                case STRING:
                    String stringValue = value.textValue();
                    if (stringValue.contains("\"")) {
                        log.debug("remove double quotes");
                        String stripped = stringValue.substring(1, stringValue.length()-1);
                        fields.put(field, stripped);
                    }
                    fields.put(field, value.textValue());
                    break;
                default:
                    log.debug("no implementation for type {}", nodeType.name());
            }
        });
        log.debug("fields: {}", fields);
        return fields;
    }
}
