package ru.yandex.webmaster3.worker.oldwmc;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.oldwebmaster.compatibility.VerificationStateEnum;
import ru.yandex.oldwebmaster.compatibility.VerificationTypeEnum;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.core.host.verification.UserHostVerificationInfo;
import ru.yandex.webmaster3.core.host.verification.VerificationFailInfo;
import ru.yandex.webmaster3.core.host.verification.VerificationStatus;
import ru.yandex.webmaster3.core.host.verification.VerificationType;
import ru.yandex.webmaster3.core.http.HttpConstants;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.user.UserVerifiedHost;
import ru.yandex.webmaster3.core.util.OldWmcVerificationUtil;
import ru.yandex.webmaster3.core.util.URLEncodeUtil;
import ru.yandex.webmaster3.storage.user.dao.UserHostVerificationYDao;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;

/**
 * @author avhaliullin
 */
public class OldWmcVerificationsService {
    private static final ObjectMapper OM = new ObjectMapper();
    private static final String SYNC_VERIFICATION_STATE_ACTION = "/xml/syncVerificationState";

    private CloseableHttpClient httpClient;

    private String apiUrl;
    private UserHostVerificationYDao userHostVerificationYDao;
    private UserHostsService userHostsService;

    public void init() {
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000)
                .setConnectTimeout(HttpConstants.DEFAULT_CONNECT_TIMEOUT)
                .build();

        httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionTimeToLive(30, TimeUnit.SECONDS)
                .build();
    }

    private void syncVerificationState(long userId, WebmasterHostId hostId, VerificationStateEnum state, VerificationTypeEnum type, Long uin) {
        StringBuilder qb = new StringBuilder(apiUrl + SYNC_VERIFICATION_STATE_ACTION + ".json?userId=" + userId +
                "&hostId=" + URLEncodeUtil.urlEncode(hostId.toString()));
        if (state != null) {
            qb.append("&state=" + state);
        }
        if (type != null) {
            qb.append("&type=" + type);
        }
        if (uin != null) {
            qb.append("&uin=" + uin);
        }
        HttpGet query = new HttpGet(qb.toString());
        try (CloseableHttpResponse response = httpClient.execute(query)) {
            JsonNode result = null;
            if (response.getStatusLine().getStatusCode() == 200) {
                result = OM.readTree(response.getEntity().getContent());
                if (!result.has("errors")) {
                    return;
                }
            }
            throw new WebmasterException("Failed to sync verification " +
                    response.getStatusLine().getStatusCode() + (result == null ? "" : " and response " + result),
                    new WebmasterErrorResponse.InternalUnknownErrorResponse(getClass(), null));
        } catch (IOException e) {
            throw new WebmasterException("Failed to sync verification",
                    new WebmasterErrorResponse.InternalUnknownErrorResponse(getClass(), null), e);
        }
    }

    public void syncVerificationState(long userId, WebmasterHostId hostId) {
        try {
            UserVerifiedHost userVerifiedHost =
                    userHostsService.getVerifiedHost(new WebmasterUser(userId), hostId);
            VerificationStatus verificationStatus = null;
            VerificationType verificationType = null;
            Long uin = null;
            VerificationFailInfo failInfo = null;
            if (userVerifiedHost != null) {
                uin = userVerifiedHost.getVerificationUin();
                verificationStatus = VerificationStatus.VERIFIED;
                verificationType = userVerifiedHost.getVerificationType();
            } else {
                UserHostVerificationInfo verificationInfo = userHostVerificationYDao.getLatestRecord(
                        userId,
                        hostId
                );
                if (verificationInfo != null && verificationInfo.isAddedToList()) {
                    verificationStatus = verificationInfo.getVerificationStatus();
                    uin = verificationInfo.getVerificationUin();
                    verificationType = verificationInfo.getVerificationType();
                    failInfo = verificationInfo.getVerificationFailInfo();
                }
            }
            Pair<VerificationStateEnum, VerificationTypeEnum> stateAndType =
                    OldWmcVerificationUtil.convertVerificationInfo(
                            verificationStatus, verificationType, failInfo
                    );

            syncVerificationState(userId, hostId,
                    stateAndType.getLeft(), stateAndType.getRight(), uin);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to sync verification state",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    @Required
    public void setApiUrl(String apiUrl) {
        this.apiUrl = apiUrl;
    }

    @Required
    public void setUserHostVerificationYDao(UserHostVerificationYDao userHostVerificationYDao) {
        this.userHostVerificationYDao = userHostVerificationYDao;
    }

    @Required
    public void setUserHostsService(UserHostsService userHostsService) {
        this.userHostsService = userHostsService;
    }
}
