package ru.yandex.webmaster.periodic.contentpreview;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.WritableResource;

import ru.yandex.common.scheduler.ExecutionContext;
import ru.yandex.kungfu.application.ApplicationResources;
import ru.yandex.webmaster.common.contentpreview.ContentPreviewSettings;
import ru.yandex.webmaster.common.contentpreview.ContentPreviewSettingsService;
import ru.yandex.webmaster.common.contentpreview.ContentPreviewState;
import ru.yandex.webmaster.common.contentpreview.ContentPreviewType;
import ru.yandex.webmaster.common.host.dao.TblHostsMainDao;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.InternalProblem;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.servantlet.AbstractServantlet;
import ru.yandex.wmtools.common.util.scheduler.timetable.AbstractTaskExecutor;

/**
 * @author aherman
 */
public class ExportContentPreviewSettingsTask extends AbstractTaskExecutor {
    private static final Logger log = LoggerFactory.getLogger(ExportContentPreviewSettingsTask.class);
    private static final DateTimeFormatter FORMAT = DateTimeFormat.forPattern("yyyyMMdd_HH_mm_ss");

    private ContentPreviewSettingsService contentPreviewSettingsService;
    private ApplicationResources applicationResources;
    private TblHostsMainDao tblHostsMainDao;

    @Override
    public String runWithRELogging(ExecutionContext context) throws InternalException {
        log.info("Start content preview settings export");

        Iterator<List<ContentPreviewSettings>> allSettings = contentPreviewSettingsService.getAllSettings();
        DateTime now = DateTime.now();
        String exportFileName = "webmaster.content_preview_settings." + FORMAT.print(now) + ".xml.gz";
        OutputStream os = null;
        int hostCount = 0;
        try {
            WritableResource exportResource = applicationResources.getResourceInData(exportFileName);
            log.info("Save to file: {}", exportResource.getFile().getAbsolutePath());
            os = new GZIPOutputStream(exportResource.getOutputStream());
            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
            XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(os);
            xmlStreamWriter.writeStartDocument();
            hostCount = saveSettings(xmlStreamWriter, allSettings);
            xmlStreamWriter.writeEndDocument();
        } catch (IOException e) {
            throw new InternalException(InternalProblem.PROCESSING_ERROR, "Unable to save export file", e);
        } catch (XMLStreamException e) {
            throw new InternalException(InternalProblem.PROCESSING_ERROR, "Unable to save export file", e);
        } catch (UserException e) {
            throw new InternalException(InternalProblem.PROCESSING_ERROR, "Unable to save export file", e);
        } finally {
            IOUtils.closeQuietly(os);
        }

        return "Settings saved for " + hostCount + " hosts";
    }

    private int saveSettings(XMLStreamWriter xmlStreamWriter, Iterator<List<ContentPreviewSettings>> allSettings)
            throws XMLStreamException, InternalException, UserException
    {
        xmlStreamWriter.writeStartElement("content-preview");
        int hostCount = 0;
        while (allSettings.hasNext()) {
            hostCount++;
            List<ContentPreviewSettings> settings = allSettings.next();
            BriefHostInfo hostInfo = tblHostsMainDao.getBriefHostInfoByHostId(settings.get(0).getHostId());
            xmlStreamWriter.writeStartElement("host");

            xmlStreamWriter.writeStartElement("name");
            xmlStreamWriter.writeCharacters(AbstractServantlet.prepareUrl(hostInfo.getName(), false).toExternalForm());
            xmlStreamWriter.writeEndElement(); // name

            for (ContentPreviewSettings setting : settings) {
                if (setting.getType() == ContentPreviewType.UNKNOWN || setting.getState() == ContentPreviewState.UNKNOWN) {
                    continue;
                }
                xmlStreamWriter.writeStartElement("preview");
                xmlStreamWriter.writeAttribute("type", setting.getType().name());
                xmlStreamWriter.writeAttribute("state", setting.getState().name());
                xmlStreamWriter.writeEndElement(); // preview
            }

            xmlStreamWriter.writeEndElement(); // host

            if (hostCount % 1000 == 0) {
                log.debug("Progress: {} hosts", hostCount);
            }
        }
        xmlStreamWriter.writeEndElement(); // content-preview
        return hostCount;
    }

    @Required
    public void setContentPreviewSettingsService(ContentPreviewSettingsService contentPreviewSettingsService) {
        this.contentPreviewSettingsService = contentPreviewSettingsService;
    }

    @Required
    public void setApplicationResources(ApplicationResources applicationResources) {
        this.applicationResources = applicationResources;
    }

    @Required
    public void setTblHostsMainDao(TblHostsMainDao tblHostsMainDao) {
        this.tblHostsMainDao = tblHostsMainDao;
    }
}
