package ru.yandex.wmconsole.verification;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.wmconsole.data.VerificationStateEnum;
import ru.yandex.wmconsole.data.info.UsersHostsInfo;
import ru.yandex.wmtools.common.SupportedProtocols;
import ru.yandex.wmtools.common.sita.DocumentFormatEnum;
import ru.yandex.wmtools.common.sita.RedirectConfig;
import ru.yandex.wmtools.common.sita.SitaException;
import ru.yandex.wmtools.common.sita.SitaRedirectCycleException;
import ru.yandex.wmtools.common.sita.SitaRedirectService;
import ru.yandex.wmtools.common.sita.SitaRequestTimeout;
import ru.yandex.wmtools.common.sita.SitaUrlFetchRequest;
import ru.yandex.wmtools.common.sita.SitaUrlFetchRequestBuilder;
import ru.yandex.wmtools.common.sita.SitaUrlFetchResponse;
import ru.yandex.wmtools.common.sita.UserAgentEnum;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

/**
 * @author ailyin
 */
public class MetaTagVerifier extends ConsistentVerifier {
    private static final Logger log = LoggerFactory.getLogger(MetaTagVerifier.class);

    private int socketTimeoutMillis = 10000;
    private SitaRedirectService sitaNoCheckRedirectService;
    private static final RedirectConfig REDIRECT_CONFIG = new RedirectConfig(5);

    @Override
    public UsersHostsInfo verify(UsersHostsInfo verInfo) {
        URL urlAddress = getMetaTagVerificationAddress(verInfo.getHostName());

        SitaUrlFetchResponse sitaUrlFetchResponse;
        try {
            SitaUrlFetchRequest sitaUrlFetchRequest = new SitaUrlFetchRequestBuilder(urlAddress)
                    .setUserAgent(UserAgentEnum.WEBMASTER)
                    .setCheckAllowedInRobotsTxt(false)
                    .setDocumentFormat(DocumentFormatEnum.DF_HTTP_RESPONSE)
                    .setRequestTimeout(SitaRequestTimeout._15_SECONDS)
                    .createSitaUrlFetchRequest();
            sitaUrlFetchRequest.setSitaSocketTimeoutMillis(socketTimeoutMillis);

            sitaUrlFetchResponse = sitaNoCheckRedirectService
                    .followRedirects(sitaUrlFetchRequest, REDIRECT_CONFIG);

            if (YandexHttpStatus.isStandardHttpCode(sitaUrlFetchResponse.getSitaHttpStatus())
                    && sitaUrlFetchResponse.getSitaHttpStatus() != YandexHttpStatus.HTTP_200_OK) {
                int code = sitaUrlFetchResponse.getSitaHttpStatus().getCode();
                String verifyFaultLog = "SAX. Checking meta-tag: Not verified: Bad http code: " +
                        code + " for " + urlAddress;
                log.debug(verifyFaultLog);
                return UsersHostsInfo.createNotVerifiedNow(
                        verInfo, VerificationStateEnum.META_TAG_IO_EXCEPTION, verifyFaultLog, code);
            }
        } catch (SitaRedirectCycleException e) {
            String verifyFaultLog = "Unable to download file " + urlAddress + " due to cyclic redirection";
            log.debug(verifyFaultLog);
            return UsersHostsInfo.createNotVerifiedNow(verInfo, VerificationStateEnum.META_TAG_IO_EXCEPTION, verifyFaultLog);
        } catch (SitaException e) {
            String verifyFaultLog = "Unable to download file " + urlAddress;
            log.debug(verifyFaultLog, e);
            return UsersHostsInfo.createNotVerifiedNow(verInfo, VerificationStateEnum.META_TAG_IO_EXCEPTION, verifyFaultLog);
        } catch (Exception e) {
            String verifyFaultLog = "Unable to download file " + urlAddress;
            log.debug(verifyFaultLog, e);
            return UsersHostsInfo.createNotVerifiedNow(verInfo, VerificationStateEnum.META_TAG_IO_EXCEPTION, verifyFaultLog);
        }

        MetaTagChecker checker = new JerichoMetaTagChecker();

        return checker.checkMetatag(verInfo, urlAddress, sitaUrlFetchResponse);
    }

    private URL getMetaTagVerificationAddress(String hostname) {
        try {
            return SupportedProtocols.getURL(hostname.toLowerCase());
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("invalid hostname has been passed", e);
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("invalid hostname has been passed", e);
        } catch (SupportedProtocols.UnsupportedProtocolException e) {
            throw new IllegalArgumentException("hostname with unsupported protocol has been passed", e);
        }
    }

    public static interface MetaTagChecker {
        public UsersHostsInfo checkMetatag(UsersHostsInfo verInfo, URL urlAddress,
                SitaUrlFetchResponse sitaUrlFetchResponse);
    }

    @Required
    public void setSitaNoCheckRedirectService(SitaRedirectService sitaNoCheckRedirectService) {
        this.sitaNoCheckRedirectService = sitaNoCheckRedirectService;
    }
}
