package ru.yandex.wmconsole.servantlet;

import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.error.ClientException;
import ru.yandex.wmconsole.error.ClientProblem;
import ru.yandex.wmconsole.service.HostInfoService;
import ru.yandex.wmconsole.service.UsersHostsService;
import ru.yandex.wmconsole.service.VerifyService;
import ru.yandex.wmconsole.service.WMCUserInfoService;
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.error.UserProblem;
import ru.yandex.wmtools.common.servantlet.AuthenticationServantlet;
import ru.yandex.wmtools.common.service.ISupportService;

public abstract class WMCAuthenticationServantlet extends AuthenticationServantlet {
    protected static final String PARAM_USER = "user";

    private WMCUserInfoService userInfoService;
    private UsersHostsService usersHostsService;
    private HostInfoService hostInfoService;
    private VerifyService verifyService;
    private BriefHostInfoHelper hostInfoHelper;

    protected BriefHostInfo getHostInfo(ServRequest req, long userId, boolean assertHostAdded, boolean assertHostVerified)
            throws ClientException, InternalException {
        return hostInfoHelper.getHostInfo(req, userId, assertHostAdded, assertHostVerified);
    }

    /**
     * Retrieves host information from database, using http request parameters, and makes several base checks.
     *
     * @param req                Http request.
     * @param assertHostIndexed  Do you want this method to assert that host is indexed.
     * @param userId             Id of user, for what assertHostAdded and assertHostVerified will be checked. Needed only if one of the following assertions will be checked.
     * @param assertHostAdded    Do you want this method to assert that host is added by given user.
     * @param assertHostVerified Do you want this method to assert that host is verified by given user. If this parameter is set to <code>true</code>, assertHostAdded must also be true.
     * @return Returns BriefHostInfo object for host, requested in http parameters.
     * @throws ru.yandex.wmconsole.error.ClientException
     *                           Thrown if some error occured.
     * @throws InternalException Thrown if some error occured.
     */
    protected BriefHostInfo getHostInfo(ServRequest req, boolean assertHostIndexed, long userId, boolean assertHostAdded,
                                        boolean assertHostVerified) throws ClientException, InternalException {
        return hostInfoHelper.getHostInfo(req, assertHostIndexed, userId, assertHostAdded, assertHostVerified);
    }

    /**
     * Retrieves host information from database, using http request parameters, and makes several base checks.
     *
     * @param req                      Http request.
     * @param assertHostIndexed        Do you want this method to assert that host is indexed.
     * @param userId                   Id of user, for what assertHostAdded and assertHostVerified will be checked. Needed only if one of the following assertions will be checked.
     * @param assertHostAdded          Do you want this method to assert that host is added by given user.
     * @param assertHostVerified       Do you want this method to assert that host is verified by given user. If this parameter is set to <code>true</code>, assertHostAdded must also be true.
     * @param res                      Http response.
     * @param showHostDataFirstLoading If host is in "first data loading" state, write corresponding tag into response.
     * @param returnNullIfHostDataFirstLoading
     *                                 If host is in "first data loading" state, return null instead of briefHostInfo object.
     * @return Returns BriefHostInfo object for host, requested in http parameters.
     * @throws ClientException   Thrown if some error occured.
     * @throws InternalException Thrown if some error occured.
     */
    protected BriefHostInfo getHostInfo(ServRequest req, boolean assertHostIndexed, long userId, boolean assertHostAdded,
                                        boolean assertHostVerified, ServResponse res, boolean showHostDataFirstLoading,
                                        boolean returnNullIfHostDataFirstLoading) throws ClientException, InternalException {
        return hostInfoHelper.getHostInfo(req, assertHostIndexed, userId, assertHostAdded, assertHostVerified, res,
                showHostDataFirstLoading, returnNullIfHostDataFirstLoading);
    }

    protected BriefHostInfo getHostInfoAndVerify(ServRequest req, long userId)
            throws UserException, InternalException {
        return hostInfoHelper.getHostInfoAndVerify(req, userId);
    }

    protected BriefHostInfo getHostInfoAndCheckHostAdded(ServRequest req, long userId)
            throws ClientException, InternalException {
        return hostInfoHelper.getHostInfoAndCheckHostAdded(req, userId);
    }

    protected BriefHostInfo getHostInfo(ServRequest req, boolean nullable) throws ClientException, InternalException {
        return hostInfoHelper.getHostInfo(req, nullable);
    }

    protected BriefHostInfo getHostInfo(ServRequest req) throws ClientException, InternalException {
        return hostInfoHelper.getHostInfo(req);
    }

    protected long getAndCheckUserIdByNameOrId(ServRequest req, String paramName)
            throws UserException, InternalException {
        Long userId = getUserIdByNameOrId(req, paramName);
        if (!userInfoService.isKnownUser(userId)) {
            throw new UserException(UserProblem.NO_SUCH_USER_IN_SERVICE,
                    "No such user in WMConsole: " + getRequiredStringParam(req, paramName));
        }
        return userId;
    }

    protected long getUserIdByNameOrId(ServRequest req, String paramName)
            throws UserException {
        String givenUser = getRequiredStringParam(req, paramName);
        return userInfoService.getUserIdByNameOrId(givenUser, paramName);
    }

    protected long getAndCheckUserIdByNameOrId(ServRequest req)
            throws UserException, InternalException {
        return getAndCheckUserIdByNameOrId(req, PARAM_USER);
    }

    public String bringToStandardWwwPrefix(String doubtfulWww, String standardWww) {
        if (doubtfulWww.toLowerCase().startsWith("www.") && (!standardWww.toLowerCase().startsWith("www."))) {
            // remove "www." from url
            return doubtfulWww.substring(4);
        }

        if (!doubtfulWww.toLowerCase().startsWith("www.") && (standardWww.toLowerCase().startsWith("www."))) {
            // add "www." to url
            return "www." + doubtfulWww;
        }

        return doubtfulWww;
    }

    public void assertUserExists(long userId) throws InternalException {
        if (userInfoService.getPassportUserInfo(userId) == null) {
            throw new InternalException(InternalProblem.NO_SUCH_USER_IN_PASSPORT, "User " + userId + " not found in passport");
        }
    }

    /**
     * Проверяет, проиндексирован ли сайт обычным роботом или быстророботом
     *
     * @throws ClientException исключение в случае, если сайт не проиндексирован
     */
    public void checkIndexed(BriefHostInfo briefHostInfo) throws InternalException, ClientException {
        if (!hostInfoService.isIndexed(briefHostInfo) && !hostInfoService.isQuickIndexed(briefHostInfo)) {
            throw new ClientException(ClientProblem.HOST_NOT_INDEXED, "Host is not indexed");
        }
    }

    protected WMCUserInfoService getUserInfoService() {
        return userInfoService;
    }

    @Required
    public void setUserInfoService(WMCUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    protected UsersHostsService getUsersHostsService() {
        return usersHostsService;
    }

    @Required
    public void setUsersHostsService(UsersHostsService usersHostsService) {
        this.usersHostsService = usersHostsService;
    }

    protected HostInfoService getHostInfoService() {
        return hostInfoService;
    }

    @Required
    public void setHostInfoService(HostInfoService hostInfoService) {
        this.hostInfoService = hostInfoService;
    }

    @Required
    public void setVerifyService(VerifyService verifyService) {
        this.verifyService = verifyService;
    }

    protected VerifyService getVerifyService() {
        return verifyService;
    }

    @Required
    public void setHostInfoHelper(BriefHostInfoHelper hostInfoHelper) {
        this.hostInfoHelper = hostInfoHelper;
    }
}
