package ru.yandex.wmconsole.viewer.api.servantlet.history;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.common.util.collections.Pair;
import ru.yandex.webmaster.common.urltree.YandexSearchShard;
import ru.yandex.webmaster.common.util.xml.SimpleXmlBuilder;
import ru.yandex.wmconsole.data.IndexingEntityEnum;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.error.ClientException;
import ru.yandex.wmconsole.servantlet.api.AbstractApiServantlet;
import ru.yandex.wmconsole.service.HostDbHostInfoService;
import ru.yandex.wmconsole.service.IndexHistoryService;
import ru.yandex.wmconsole.service.dao.TblUrlTreesDao;
import ru.yandex.wmconsole.viewer.api.SiteHistoryType;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.util.XmlDataWrapper;

/**
 * @author aherman
 */
public abstract class AbstractApiGetHistoryServantlet extends AbstractApiServantlet {
    protected IndexHistoryService indexHistoryService;
    private TblUrlTreesDao tblUrlTreesDao;
    private HostDbHostInfoService hostDbHostInfoService;

    @Override
    protected void apiDoProcess(ServRequest req, ServResponse res, long userId) throws ClientException, InternalException {

        BriefHostInfo briefHostInfo = getHostInfo(req, false, userId, true, true, res, false, false);
        SiteHistoryType historyType = getHistoryType();
        NavigableMap<Date, Long> historyData = getHistoryData(briefHostInfo, historyType, userId);
        List<Pair<DateTime, Long>> result = new ArrayList<Pair<DateTime, Long>>();
        for (Map.Entry<Date, Long> entry : historyData.entrySet()) {
            if (entry.getValue() != null) {
                result.add(Pair.of(new DateTime(entry.getKey().getTime()), entry.getValue()));
            }
        }
        result = filterData(result);
        res.addData(new HistoryDataWrapper(result, historyType));
    }

    protected NavigableMap<Date, Long> getHistoryData(BriefHostInfo briefHostInfo, SiteHistoryType historyType, long userId)
            throws InternalException
    {
        IndexingEntityEnum indexingEntityEnum = convert(historyType);
        YandexSearchShard searchShard = YandexSearchShard.RU;
        if (indexingEntityEnum.isEntityForSearchShard()) {
            HostDbHostInfo hostDbHostInfo = hostDbHostInfoService.getHostDbHostInfo(briefHostInfo.getName());
            searchShard = tblUrlTreesDao.getOptimumShardId(hostDbHostInfo);
        }
        return indexHistoryService.getIndexHistoryPlotData(briefHostInfo, indexingEntityEnum, null, searchShard);
    }

    private IndexingEntityEnum convert(SiteHistoryType historyType) {
        switch(historyType) {
            case TIC: return IndexingEntityEnum.TCY;
            case CRAWLED_URLS_COUNT: return IndexingEntityEnum.ROBOTDB_INFO_URLS;
            case INDEXED_URLS_COUNT: return IndexingEntityEnum.ROBOTDB_INFO_INDEX_COUNT;
            case INCOMING_LINKS_COUNT: return IndexingEntityEnum.LINKS_COUNT;
        }

        throw new IllegalArgumentException("Unsupported history type: " + historyType);
    }

    protected LocalDate toStartOfMonth(DateTime dateTime) {
        return dateTime.withDayOfMonth(1).withMillisOfDay(0).toLocalDate();
    }

    protected List<Pair<DateTime,Long>> filterData(List<Pair<DateTime,Long>> data) {
        return data;
    }

    protected abstract SiteHistoryType getHistoryType();

    protected static class HistoryDataWrapper extends XmlDataWrapper<List<Pair<DateTime, Long>>> {
        private final DateTimeFormatter FORMATTER = ISODateTimeFormat.date();
        private final SiteHistoryType type;

        public HistoryDataWrapper(List<Pair<DateTime, Long>> data, SiteHistoryType type) {
            super(data);
            this.type = type;
        }

        @Override
        protected void doToXml(StringBuilder result) {
            SimpleXmlBuilder xml = new SimpleXmlBuilder(result);
            xml.open("history").attribute("type", type);
            for (Pair<DateTime, Long> pair : data) {
                xml.open("value").attribute("date", FORMATTER.print(pair.getFirst()));
                xml.text(pair.getSecond());
                xml.close(); // value
            }
            xml.close(); // history
        }
    }

    @Required
    public void setIndexHistoryService(IndexHistoryService indexHistoryService) {
        this.indexHistoryService = indexHistoryService;
    }

    @Required
    public void setTblUrlTreesDao(TblUrlTreesDao tblUrlTreesDao) {
        this.tblUrlTreesDao = tblUrlTreesDao;
    }

    @Required
    public void setHostDbHostInfoService(HostDbHostInfoService hostDbHostInfoService) {
        this.hostDbHostInfoService = hostDbHostInfoService;
    }
}
