package ru.yandex.direct.api.v5.entity.changes.converter;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.yandex.direct.api.v5.changes.CampaignChangesInEnum;
import com.yandex.direct.api.v5.changes.CampaignChangesItem;
import com.yandex.direct.api.v5.changes.CampaignStatItem;
import com.yandex.direct.api.v5.changes.CheckCampaignsResponse;
import com.yandex.direct.api.v5.changes.CheckFieldEnum;
import com.yandex.direct.api.v5.changes.CheckRequest;
import com.yandex.direct.api.v5.changes.CheckResponse;
import com.yandex.direct.api.v5.changes.CheckResponseIds;
import com.yandex.direct.api.v5.changes.CheckResponseModified;

import ru.yandex.direct.core.entity.changes.model.CheckCampaignsIntResp;
import ru.yandex.direct.core.entity.changes.model.CheckIntReq;
import ru.yandex.direct.core.entity.changes.model.CheckIntResp;

import static org.apache.commons.collections4.CollectionUtils.isEmpty;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.apache.commons.collections4.MapUtils.isNotEmpty;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.ModifiedAdGroupIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.ModifiedAdIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.ModifiedCampaignIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.NotFoundAdGroupIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.NotFoundAdIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.NotFoundCampaignIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.UnprocessedAdGroupIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.UnprocessedAdIds;
import static ru.yandex.direct.core.entity.changes.model.CheckIntResp.ParamBlock.UnprocessedCampaignIds;
import static ru.yandex.direct.utils.CollectionUtils.nullIfEmpty;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

public class ChangesCommonConvertUtil {

    // functions for changes.checkCampaigns

    private static CampaignChangesItem convertCheckCampaignsInternalResult(CheckCampaignsIntResp internalResult) {
        CampaignChangesItem item = new CampaignChangesItem();
        item.setCampaignId(internalResult.getCampaignId());
        item.setChangesIn(new ArrayList<>(3));
        if (internalResult.isSelfChanged()) {
            item.getChangesIn().add(CampaignChangesInEnum.SELF);
        }
        if (internalResult.isChildrenChanged()) {
            item.getChangesIn().add(CampaignChangesInEnum.CHILDREN);
        }
        if (internalResult.isStatChanged()) {
            item.getChangesIn().add(CampaignChangesInEnum.STAT);
        }
        return item;
    }

    public static CheckCampaignsResponse convertCheckCampaignsResult(List<CheckCampaignsIntResp> internalResults,
                                                                     String timestamp) {
        CheckCampaignsResponse response = new CheckCampaignsResponse();
        response.setCampaigns(isEmpty(internalResults) ? null :
                mapList(internalResults, ChangesCommonConvertUtil::convertCheckCampaignsInternalResult));
        response.setTimestamp(timestamp);
        return response;
    }

    // functions for changes.check

    public static CheckIntReq convertCheckRequest(CheckRequest externalRequest) {
        return new CheckIntReq(
                new HashSet<>(externalRequest.getCampaignIds()),
                new HashSet<>(externalRequest.getAdGroupIds()),
                new HashSet<>(externalRequest.getAdIds()),
                ChangesDateTimeConvertUtil.convertUtcTimestampToMoscowDateTime(externalRequest.getTimestamp()),
                externalRequest.getFieldNames().contains(CheckFieldEnum.CAMPAIGN_IDS),
                externalRequest.getFieldNames().contains(CheckFieldEnum.AD_GROUP_IDS),
                externalRequest.getFieldNames().contains(CheckFieldEnum.AD_IDS),
                externalRequest.getFieldNames().contains(CheckFieldEnum.CAMPAIGNS_STAT)
        );
    }

    public static CheckResponse convertCheckResult(CheckIntResp internalResponse) {

        CheckResponseModified checkResponseModified = new CheckResponseModified();
        checkResponseModified.setCampaignIds(nullIfEmpty(internalResponse.getIds(ModifiedCampaignIds)));
        checkResponseModified.setAdGroupIds(nullIfEmpty(internalResponse.getIds(ModifiedAdGroupIds)));
        checkResponseModified.setAdIds(nullIfEmpty(internalResponse.getIds(ModifiedAdIds)));

        Map<Long, LocalDate> campaignIdToBorderDateMap = internalResponse.getCampaignIdToBorderDateMap();
        if (isNotEmpty(campaignIdToBorderDateMap)) {
            checkResponseModified.setCampaignsStat(
                    mapList(
                            campaignIdToBorderDateMap.entrySet(),
                            e -> createCampaignStatItem(e.getKey(), e.getValue())
                    )
            );
        }

        CheckResponse checkResponse = new CheckResponse();
        checkResponse.setModified(checkResponseModified);
        checkResponse.setNotFound(createCheckResponseIds(
                internalResponse.getIds(NotFoundCampaignIds),
                internalResponse.getIds(NotFoundAdGroupIds),
                internalResponse.getIds(NotFoundAdIds)
        ));
        checkResponse.setUnprocessed(createCheckResponseIds(
                internalResponse.getIds(UnprocessedCampaignIds),
                internalResponse.getIds(UnprocessedAdGroupIds),
                internalResponse.getIds(UnprocessedAdIds)
        ));
        checkResponse.setTimestamp(ChangesDateTimeConvertUtil.createNowUtcTimestampStr()); // текущее время - в респонс
        return checkResponse;
    }

    private static CheckResponseIds createCheckResponseIds(
            List<Long> campaignIds,
            List<Long> adGroupIds,
            List<Long> adIds
    ) {
        if (isNotEmpty(campaignIds) || isNotEmpty(adGroupIds) || isNotEmpty(adIds)) {
            CheckResponseIds checkResponseIds = new CheckResponseIds();
            checkResponseIds.setCampaignIds(nullIfEmpty(campaignIds));
            checkResponseIds.setAdGroupIds(nullIfEmpty(adGroupIds));
            checkResponseIds.setAdIds(nullIfEmpty(adIds));
            return checkResponseIds;
        }
        return null;
    }

    private static CampaignStatItem createCampaignStatItem(Long campaignId, LocalDate borderDate) {
        CampaignStatItem campaignStatItem = new CampaignStatItem();
        campaignStatItem.setCampaignId(campaignId);
        campaignStatItem.setBorderDate(borderDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
        return campaignStatItem;
    }
}
