package ru.yandex.webmaster3.viewer.http.turbo.feed;

import java.net.URI;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.feeds.mbi.ChangeRevokeStatusException;
import ru.yandex.webmaster3.core.host.service.HostOwnerService;
import ru.yandex.webmaster3.core.http.RequestQueryProperty;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.http.WriteAction;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.turbo.ValidateTurboFeedTaskData;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedInfo;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedSettings;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedState;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedType;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.WwwUtil;
import ru.yandex.webmaster3.core.worker.client.WorkerClient;
import ru.yandex.webmaster3.storage.feeds.FeedsNative2YDao;
import ru.yandex.webmaster3.storage.turbo.dao.TurboFeedsSettingsYDao;
import ru.yandex.webmaster3.storage.turbo.service.TurboFeedsService;
import ru.yandex.webmaster3.storage.turbo.service.settings.TurboSettingsService;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostAction;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostRequest;
import ru.yandex.webmaster3.viewer.http.turbo.feed.AddTurboFeedAction.Request;
import ru.yandex.wmtools.common.util.uri.WebmasterUriUtils;

/**
 * Created by Oleg Bazdyrev on 06/07/2017.
 */
@Slf4j
@WriteAction
@Category("turbo")
@Component("/turbo/feed/add")
@Description("Добавляет фид для турбо (не должно быть сторонних фидов)")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class AddTurboFeedAction extends AbstractUserVerifiedHostAction<Request, AddTurboFeedResponse> {

    private final FeedsNative2YDao feedsNative2YDao;
    private final HostOwnerService hostOwnerService;
    private final TurboFeedsService turboFeedsService;
    private final TurboFeedsSettingsYDao turboFeedsSettingsYDao;
    private final TurboSettingsService turboSettingsService;
    private final UserHostsService userHostsService;
    private final WorkerClient workerClient;
    @Value("${webmaster3.viewer.turbo.maxFeedsPerHost}")
    private final int maxFeedsPerHost;
    @Value("#{'${webmaster3.viewer.turbo.hostWhiteList}'.split(',')}")
    private final Set<String> hostWhiteList;

    @Override
    public AddTurboFeedResponse process(Request request) {
        try {
            WebmasterHostId hostId = request.getHostId();
            String domain = WwwUtil.cutWWWAndM(hostId);
            // проверим тип фида (пока можно только RSS)
            TurboFeedType feedType = request.feedType;
            if (feedType != TurboFeedType.RSS && feedType != TurboFeedType.YML) {
                throw new WebmasterException("Unsupported feed type " + feedType,
                        new WebmasterErrorResponse.IllegalParameterValueResponse(getClass(), "feedType", feedType.name()));
            }
            String feedUrl;
            if (request.feedUrl.startsWith("/")) {
                // если перед нами относительная ссылка
                feedUrl = IdUtils.hostIdToUrl(hostId) + request.feedUrl;
            } else {
                // перед нами абсолютная ссылка
                feedUrl = request.feedUrl;
                // проверим хост
                URI uri = WebmasterUriUtils.toOldUri(request.feedUrl);
                WebmasterHostId urlHostId = IdUtils.urlToHostId(uri.toString());
                if (!checkHost(request.getUserId(), hostId, urlHostId)) {
                    return new AddTurboFeedResponse.UrlIsNotFromHostErrorResponse();
                }
            }
            feedUrl = WebmasterUriUtils.toOldUri(feedUrl).toASCIIString();
            // проверяем, что такого фида нет нигде (в том числе в админке фидов)
            if (feedsNative2YDao.containsNonGoodsFeed(feedUrl)) {
                return new AddTurboFeedResponse.FeedAlreadyAddedErrorResponse();
            }

            // добавляем, проверим, нет ли уже такого
            List<TurboFeedSettings> feeds = turboFeedsService.getFeeds(domain).stream()
                    .filter(tfs -> tfs.getType().isInternal()).collect(Collectors.toList());
            for (TurboFeedSettings feed : feeds) {
                if (feedUrl.equals(feed.getUrl())) {
                    return new AddTurboFeedResponse.FeedAlreadyAddedErrorResponse();
                }
            }
            // проверим квоту
            if (feeds.size() >= maxFeedsPerHost) {
                return new AddTurboFeedResponse.QuotaExceededErrorResponse();
            }
            // добавляем
            TurboFeedSettings feed = TurboFeedSettings.internalFeed(hostId, feedType, feedUrl, false,
                    TurboFeedState.VALIDATING, DateTime.now(), DateTime.now());
            try {
                turboFeedsService.insertFeed(feed, request.getUserId());
            } catch (ChangeRevokeStatusException e) {
                log.info("feed with url - {} and domain - {} is banned", feed, domain);
                return new AddTurboFeedResponse.BannedFeedResponse();
            }
            // обновим настройки (чтобы были хотя бы настройки по умолчанию) - костыльно
            turboSettingsService.updateSettings(hostId, turboSettingsService.getSettings(hostId));
            // запускаем задачу на валидацию фида
            workerClient.enqueueTask(new ValidateTurboFeedTaskData(hostId, feedUrl, false, feedType));
            return new AddTurboFeedResponse.NormalResponse(new TurboFeedInfo(feed, null, null));

        } catch (Exception e) {
            log.error("Error adding feed", e);
            return new AddTurboFeedResponse.InvalidFeedUrlErrorResponse();
        }
    }

    private boolean checkHost(long userId, WebmasterHostId requestHostId, WebmasterHostId feedHostId) {
        if (hostWhiteList.contains(requestHostId.getPunycodeHostname())) {
            return true;
        }
        if (hostOwnerService.getHostOwner(requestHostId.getPunycodeHostname()).equalsIgnoreCase(
                hostOwnerService.getHostOwner(feedHostId.getPunycodeHostname()))) {
            return true;
        }
        return userHostsService.isAnyHostVerified(userId, WwwUtil.domainToHostIds(WwwUtil.cutWWWAndM(feedHostId)));
    }

    public static class Request extends AbstractUserVerifiedHostRequest {
        private TurboFeedType feedType;
        private String feedUrl;

        public TurboFeedType getFeedType() {
            return feedType;
        }

        @RequestQueryProperty(required = true)
        @Description("Тип фида")
        public void setFeedType(TurboFeedType feedType) {
            this.feedType = feedType;
        }

        public String getFeedUrl() {
            return feedUrl;
        }

        @RequestQueryProperty(required = true)
        @Description("Адрес фида для добавления")
        public void setFeedUrl(String feedUrl) {
            this.feedUrl = feedUrl;
        }
    }
}
