package ru.yandex.wmconsole.servantlet.sitemaps;

import java.util.Collection;

import javax.xml.bind.JAXBException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.db.OrderByClause;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.data.info.MergedSitemapInfo;
import ru.yandex.wmconsole.data.info.SitemapNavigationInfo;
import ru.yandex.wmconsole.data.info.UrlErrorsWithCodeInfo;
import ru.yandex.wmconsole.data.sitemaps.SitemapSourceEnum;
import ru.yandex.wmconsole.data.wrappers.MergedSitemapInfoWrapper;
import ru.yandex.wmconsole.data.wrappers.UrlErrorsWithCodeInfoWrapper;
import ru.yandex.webmaster.viewer.sitemap.CurrentSitemapService;
import ru.yandex.wmconsole.servantlet.WMCAuthorizedHostOperationServantlet;
import ru.yandex.wmconsole.service.ErrorInfoService;
import ru.yandex.wmconsole.service.HostDbHostInfoService;
import ru.yandex.webmaster.common.sitemap.SitemapService;
import ru.yandex.wmconsole.util.XmlUtil;
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.util.XmlConvertableCollectionWrapper;

/**
 * @author Andrey Mima (amima@yandex-team.ru)
 */
public class SitemapErrorGroupsServantlet extends WMCAuthorizedHostOperationServantlet {
    private static final Logger log = LoggerFactory.getLogger(SitemapErrorGroupsServantlet.class);

    private static final String PARAM_SITEMAP = "sitemap";
    private static final String PARAM_SOURCE = "source";
    private static final String PARAM_INDEX = "index";

    private ErrorInfoService errorInfoService;
    private HostDbHostInfoService hostDbHostInfoService;
    private SitemapService sitemapService;
    private CurrentSitemapService currentSitemapService;

    @Override
    public void doProcess(final ServRequest req, final ServResponse res, final long userId)
            throws UserException, InternalException {

        BriefHostInfo briefHostInfo = getHostInfo(req, true, userId, true, true, res, true, true);
        if (briefHostInfo == null) {
            return;
        }
        final HostDbHostInfo hostDbHostInfo = hostDbHostInfoService.getHostDbHostInfo(briefHostInfo.getName());

        final Integer src = getRequiredIntParam(req, PARAM_SOURCE);
        final SitemapSourceEnum source = src != null ? SitemapSourceEnum.R.fromValueOrNull(src) : null;

        Long latestId = getRequiredLongParam(req, PARAM_SITEMAP);
        log.debug("raw sitemap_id = " + latestId + ", raw src = " + src);
        Long latestIndexId = getLongParam(req, PARAM_INDEX);
        log.debug("raw index_id = " + latestIndexId);

        Long searchId = null;

        if (source == SitemapSourceEnum.IN_SEARCH) {
            throw new UnsupportedOperationException("Unsupported source value " + source);
        } else if (source == SitemapSourceEnum.LATEST) {
            // convert new sitemap id to old sitemap id
            // NB! searchId might be null after assignment
            searchId = currentSitemapService.getSitemapIdInSearchByLatestSitemapId(
                    hostDbHostInfo, latestId);
            log.debug("in search sitemap_id = " + searchId);
        }

        if (searchId == null) {
            return;
        }

        final MergedSitemapInfo sitemapInfo = sitemapService.getSitemapInfo2(hostDbHostInfo, searchId, null);
        if (sitemapInfo == null) {
            // нет такого sitemap
            return;
        }
        res.addData(new MergedSitemapInfoWrapper(sitemapInfo));

        // Входящие ссылки могут быть только с source = 1, поэтому навигацию показываем по последней загруженной версии
        final SitemapNavigationInfo navigationInfo = currentSitemapService.getNavigationInfo(hostDbHostInfo, latestId, latestIndexId);
        try {
            if (navigationInfo != null) {
                res.addData(XmlUtil.xmlConvertable(navigationInfo));
            }
        } catch (JAXBException e) {
            log.error("Jaxb marshalling error ", e);
            throw new InternalException(InternalProblem.INTERNAL_PROBLEM, "Jaxb marshalling error", e);
        }

        final OrderByClause order = new OrderByClause((String) null); // do not sort
        final Collection<UrlErrorsWithCodeInfo> urlErrors;
        urlErrors = errorInfoService.getOrderedErrorGroupsListForSitemap(
                userId, briefHostInfo, order, searchId);

        final XmlConvertableCollectionWrapper wrappedUrlErrors =
                XmlConvertableCollectionWrapper.wrap(urlErrors, UrlErrorsWithCodeInfoWrapper.class, "url-errors");
        res.addData(wrappedUrlErrors);
    }

    @Required
    public void setErrorInfoService(ErrorInfoService errorInfoService) {
        this.errorInfoService = errorInfoService;
    }

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

    @Required
    public void setSitemapService(SitemapService sitemapService) {
        this.sitemapService = sitemapService;
    }

    @Required
    public void setCurrentSitemapService(CurrentSitemapService currentSitemapService) {
        this.currentSitemapService = currentSitemapService;
    }
}
