package ru.nbch.credit_tracker.service.xml.stax;

import lombok.extern.slf4j.Slf4j;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.MonitoringSignalResponse;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Signal;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Signals;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Subject;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.List;

@Slf4j
public class MonitoringSignalResponseStaxXmlWriter extends StaxXmlWriter<MonitoringSignalResponse, Subject>{

    public MonitoringSignalResponseStaxXmlWriter(String charsetName) {
        super(charsetName);
    }

    @Override
    public void writeWithStax(String filePath, MonitoringSignalResponse obj, LoaderWriter<Subject> loader) {
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath), 8 * 1024 * 1024)) {
            XMLOutputFactory output = XMLOutputFactory.newInstance();
            XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance();
            XMLEventWriter writer = output.createXMLEventWriter(bos, charsetName);
            writer = new IndentingXMLEventWriter(writer);

            writerWrapper = new WriterWrapper(xmlEventFactory, writer);
            writerWrapper.addStartDocument(charsetName);

            writerWrapper.addStartElement("MonitoringSignalResponse");
            writerWrapper.addStartElement("Subjects");


            loader.accept(subjects -> {
                try {
                    writeSubjects(subjects);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });

            writerWrapper.addEndElement("Subjects");
            writerWrapper.addEndElement("MonitoringSignalResponse");

            writerWrapper.addEndDocument();
            writerWrapper.flush();
            System.gc();
        } catch (Throwable e) {
            log.error("Error serializing object to XML string: {}", e.getMessage(), e);
            throw new IllegalStateException("cannot serialize object to XML");
        }
    }

    private void writeSubjects(List<Subject> subjects) throws Exception {
        writerWrapper.writeCollection("Subject", subjects, this::writeSubject);
    }


    private void writeSubject(Subject subject, String name) throws Exception {
        if (subject == null) {
            return;
        }
        writerWrapper.addStartElement(name);
        writerWrapper.addSimplelement("Id", subject.getId());
        writerWrapper.addSimplelement("ClientId", subject.getClientId());
        writerWrapper.addSimplelement("FlagDebt5000", subject.getFlagDebt5000() != null ? String.valueOf(subject.getFlagDebt5000()) : null);
        writerWrapper.addSimplelement("Flag90_12", subject.getFlag9012() != null ? String.valueOf(subject.getFlag9012()) : null);
        writeSignals( subject.getSignals(), "Signals");
        writerWrapper.addEndElement(name);
    }

    private void writeSignals(Signals signals,  String name) throws Exception {
        writerWrapper.addStartElement(name);
        writerWrapper.writeCollection("Signal", signals.getSignals(), this::writeSignal);
        writerWrapper.addEndElement(name);
    }

    private void writeSignal(Signal signal, String name) throws Exception  {
        writerWrapper.addStartElement(name);
        writerWrapper.addSimplelement("SignalType", String.valueOf(signal.getSignalType()));
        writerWrapper.addSimplelement("InquiryDate", signal.getInquiryDate());
        writerWrapper.addSimplelement("InquiryPurpose", String.valueOf(signal.getInquiryPurpose()));
        writerWrapper.addEndElement(name);
    }
}
