package ru.yandex.wmconsole.verification;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.w3c.dom.Node;

import ru.yandex.common.framework.user.UserInfo;
import ru.yandex.wmconsole.data.VerificationStateEnum;
import ru.yandex.wmconsole.data.info.FreeVerificationInfo;
import ru.yandex.wmconsole.data.info.UsersHostsInfo;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.service.XPathXmlSearchResultParser;
import ru.yandex.wmtools.common.util.HttpConnector;

/**
 * @author ailyin
 */
public class PDDAutoVerifier implements Verifier {
    private static final Logger log = LoggerFactory.getLogger(PDDAutoVerifier.class);

    private static final String CONFIRMED_XPATH = "/domains/domain/confirmed";
    private static final String FROM_WEBMASTER_XPATH = "/domains/domain/from_webmaster";

    private String pddUrl;

    private VerificationTypeEnum verificationType;

    public UsersHostsInfo doVerify(final UsersHostsInfo info, final VerificationStateEnum notVerifiedState) {
        try {
            log.debug("Trying to autoverify " + info.getHostName() + " for user " + info.getUserId() + " using PDD...");

            String url = pddUrl + "domain_confirmed?domain=" + info.getHostName() + "&uid=" + info.getUserId();
            InputStream stream = new HttpConnector.RequestBuilder(new URL(url))
                    .method(HttpConnector.HttpMethod.GET)
                    .allowRedirect(false)
                    .okStatusRequired(true)
                    .execute()
                    .getContent();
            String response = IOUtils.toString(stream);

            Node confirmedNode = new XPathXmlSearchResultParser(CONFIRMED_XPATH).parseResult(new StringReader(response));
            if ((confirmedNode != null) && "yes".equals(confirmedNode.getTextContent())) {
                Node fromWebmasterNode = new XPathXmlSearchResultParser(FROM_WEBMASTER_XPATH).parseResult(new StringReader(response));
                if (fromWebmasterNode != null && "yes".equals(fromWebmasterNode.getTextContent())) {
                    log.debug("PDD verification not applicable because PDD confirmed domain from WEBMASTER");
                } else {
                    log.debug("Host has been successfully verified.");
                    return UsersHostsInfo.createVerifiedNow(info, verificationType);
                }
            }
            log.debug("Host has NOT been verified.");
            return UsersHostsInfo.createNotVerifiedNow(info, VerificationStateEnum.PDD_NOT_APPLICABLE);
        } catch (InternalException e) {
            log.warn("Failed to parse pdd servant response (host has NOT been verified).", e);
            return UsersHostsInfo.createNotVerifiedNow(info,
                    VerificationStateEnum.EXTERNAL_VERIFICATION_INTERNAL_ERROR);
        } catch (IOException e) {
            log.warn("Failed to send request to pdd servant (host has NOT been verified).", e);
            return UsersHostsInfo.createNotVerifiedNow(info,
                    VerificationStateEnum.EXTERNAL_VERIFICATION_INTERNAL_ERROR);
        }
    }

    @Override
    public UsersHostsInfo verify(UsersHostsInfo info) {
        return doVerify(info, VerificationStateEnum.PDD_NOT_APPLICABLE);
    }

    @Override
    public UsersHostsInfo cancel(UsersHostsInfo info) {
        return doVerify(info, VerificationStateEnum.EXTERNAL_VERIFICATION_CANCELLED);
    }

    public Collection<FreeVerificationInfo> getHostsApplicableForAutoVerify(UserInfo userInfo) {
        // TODO implement it once
        return new ArrayList<FreeVerificationInfo>();
    }

    @Required
    public void setVerificationType(VerificationTypeEnum verificationType){
        this.verificationType = verificationType;
    }

    @Required
    public void setPddUrl(String pddUrl) {
        this.pddUrl = pddUrl;
    }
}
