package ru.yandex.webmaster3.storage.host.moderation.regions.service;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.webmaster3.core.data.L10nEnum;
import ru.yandex.webmaster3.core.data.W3RegionInfo;
import ru.yandex.webmaster3.core.regions.W3RegionsTreeService;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.storage.host.moderation.AbstractHostModerationYtService;
import ru.yandex.webmaster3.storage.host.moderation.regions.HostRegionsModerationYtRequest;
import ru.yandex.webmaster3.storage.host.moderation.regions.HostRegionsModerationYtResult;
import ru.yandex.webmaster3.storage.host.moderation.regions.dao.HostRegionsModerationYtRequestsYDao;
import ru.yandex.webmaster3.storage.util.yt.TableWriter;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @author leonidrom
 */
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class HostRegionsModerationYtService extends AbstractHostModerationYtService<HostRegionsModerationYtRequest, HostRegionsModerationYtResult> {
    private static final String REQUESTS_TABLE_SCHEMA = "[" +
            "{'name': 'Host', 'type': 'string'}, " +
            "{'name': 'CreatedDate', 'type': 'string'}, " +
            "{'name': 'RequestId', 'type': 'string'}, " +
            "{'name': 'CurrentRegions', 'type': 'any'}, " +
            "{'name': 'RequestedRegions', 'type': 'any'}, " +
            "{'name': 'AutoModeratedRegions', 'type': 'any'}, " +
            "{'name': 'NeedModerationRegions', 'type': 'any'}, " +
            "{'name': 'EvidenceUrl', 'type': 'string'}" +
            "]";

    private static final String RESULTS_TABLE_SCHEMA = "[" +
            "{'name': 'Host', 'type': 'string'}, " +
            "{'name': 'CreatedDate', 'type': 'string'}, " +
            "{'name': 'RequestId', 'type': 'string'}, " +
            "{'name': 'CurrentRegions', 'type': 'any'}, " +
            "{'name': 'RequestedRegions', 'type': 'any'}, " +
            "{'name': 'AutoModeratedRegions', 'type': 'any'}, " +
            "{'name': 'NeedModerationRegions', 'type': 'any'}, " +
            "{'name': 'AcceptedRegions', 'type': 'any'}, " +
            "{'name': 'EvidenceUrl', 'type': 'string'}, " +
            "{'name': 'ModerationDate', 'type': 'string'}, " +
            "{'name': 'Comments', 'type': 'any'}, " +
            "{'name': 'Assessor', 'type': 'string'}" +
            "]";

    private final HostRegionsModerationService hostRegionsModerationService;
    private final HostRegionsModerationYtRequestsYDao hostRegionsModerationYtRequestsYDao;
    private final W3RegionsTreeService w3regionsTreeService;

    @Override
    protected void deleteProcessedYtRequests(List<UUID> processedRequests) {
        hostRegionsModerationYtRequestsYDao.deleteRequests(processedRequests);
    }

    @Override
    protected Set<UUID> getProcessedRequestIds() {
        return Collections.emptySet();
    }

    @Override
    protected List<HostRegionsModerationYtRequest> listAllRequests() {
        List<HostRegionsModerationYtRequest> result = new ArrayList<>();
        hostRegionsModerationYtRequestsYDao.forEach(result::add);

        return result;
    }

    @Override
    protected void writeRequestColumns(TableWriter tw, HostRegionsModerationYtRequest request) {
        tw.column(YtRequestFields.HOST, IdUtils.hostIdToReadableUrl(request.getHostId()));
        tw.column(YtRequestFields.CREATED_DATE, request.getCreatedDate().toString());
        tw.column(YtRequestFields.REQUEST_ID, request.getRequestId().toString());
        tw.columnObject(YtRequestFields.CURRENT_REGIONS, regionsToRegionsWithName(request.getCurrentRegions()));
        tw.columnObject(YtRequestFields.REQUESTED_REGIONS, regionsToRegionsWithName(request.getRequestedRegions()));
        tw.columnObject(YtRequestFields.AUTO_MODERATED_REGIONS, regionsToRegionsWithName(request.getAutoModeratedRegions()));
        tw.columnObject(YtRequestFields.NEED_MODERATION_REGIONS, regionsToRegionsWithName(request.getNeedModerationRegions()));
        tw.column(YtRequestFields.EVIDENCE_URL, request.getEvidenceUrl());
    }

    @Override
    protected void writeAutoModerationResultColumns(TableWriter tw, HostRegionsModerationYtRequest request) {
        tw.column(CommonYtResultFields.MODERATION_DATE, request.getCreatedDate().toString());
        tw.column(CommonYtResultFields.ASSESSOR, AUTO_MODERATED_ASSESSOR);
    }

    @Override
    protected void processYtResult(HostRegionsModerationYtResult row) {
        Set<Integer> acceptedRegions = row.getAcceptedRegions().stream()
                .map(YtRequestRegion::getRegionId)
                .collect(Collectors.toSet());

        hostRegionsModerationService.processModerationResult(row.getRequestId(), row.getHostId(), row.getAssessor(),
                row.getModerationDate(), acceptedRegions);
    }

    @Override
    protected Class<HostRegionsModerationYtResult> getYtResultClass() {
        return HostRegionsModerationYtResult.class;
    }

    @Override
    protected String getRequestsTableSchema() {
        return REQUESTS_TABLE_SCHEMA;
    }

    @Override
    protected String getResultsTableSchema() {
        return RESULTS_TABLE_SCHEMA;
    }

    private List<YtRequestRegion> regionsToRegionsWithName(Collection<Integer> regionIds) {
        return regionIds.stream()
                .map(this::regionIdToYtRequestRegion)
                .collect(Collectors.toList());

    }

    private YtRequestRegion regionIdToYtRequestRegion(int regionId) {
        String regionName = null;
        W3RegionInfo regionInfo = w3regionsTreeService.getExactRegionInfo(regionId);
        if (regionInfo != null) {
            regionName = regionInfo.getNames().get(L10nEnum.RU);
        }

        return new YtRequestRegion(regionId, regionName);
    }


    public static class YtRequestRegion {
        private final int regionId;
        private final String regionName;

        @JsonCreator
        public YtRequestRegion(
                @JsonProperty("regionId") int regionId,
                @JsonProperty("regionName") String regionName) {
            this.regionId = regionId;
            this.regionName = regionName;
        }

        public int getRegionId() {
            return regionId;
        }

        public String getRegionName() {
            return regionName;
        }
    }

    public static class YtRequestFields extends CommonYtRequestFields {
        static final String CURRENT_REGIONS = "CurrentRegions";
        static final String REQUESTED_REGIONS = "RequestedRegions";
        static final String AUTO_MODERATED_REGIONS = "AutoModeratedRegions";
        static final String NEED_MODERATION_REGIONS = "NeedModerationRegions";
        static final String EVIDENCE_URL = "EvidenceUrl";
    }
}
