package ru.yandex.webmaster3.worker.feeds;

import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.feeds.feed.FeedsOfferBanTypeEnum;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedType;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.core.worker.task.TaskResult;
import ru.yandex.webmaster3.storage.feeds.FeedsOfferBansYDao;
import ru.yandex.webmaster3.storage.host.CommonDataState;
import ru.yandex.webmaster3.storage.settings.SettingsService;
import ru.yandex.webmaster3.storage.util.ydb.YdbYqlService;
import ru.yandex.webmaster3.storage.util.yt.YtNode;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

import static ru.yandex.webmaster3.storage.host.CommonDataType.LAST_BAN_OFFERS_IMPORT;

/**
 * Created by Oleg Bazdyrev on 20/01/2022.
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ImportFeedsOfferBansTask extends PeriodicTask<PeriodicTaskState> {

    private final YtService ytService;
    private final SettingsService settingsService;
    private final FeedsOfferBansYDao feedsOfferBansYDao;
    @Value("hahn://home/webmaster/prod/feeds/offer_bans/offer_bans_joined")
    private final YtPath tablePath;


    @Value("${external.yt.service.hahn.root.default}/export/feeds/unisearch/offer_feeds")
    private final YtPath offerFeedsPath;
    @Value("${external.yt.service.hahn.root.default}/export/feeds/unisearch/offer_feeds_moderation")
    private final YtPath offerFeedsModerationPath;

    private final YdbYqlService ydbYqlService;


    public static final String GET_INT_TYPE_QUERY = "$get_int_type = ($source) -> {\n" +
            "return CASE\n" +
            Arrays.stream(NativeFeedType.values()).map(x -> "WHEN $source = '" + x.getTypeOfferBase() + "' THEN " + x.value()).collect(Collectors.joining("\n")) +
            "\nELSE 0" +
            "\nEND" +
            "};\n\n";

    public static final String GET_INT_REASON_QUERY = "$get_int_reason = ($source) -> {\n" +
            "return CASE\n" +
            Arrays.stream(FeedsOfferBanTypeEnum.values()).map(x -> "WHEN $source = '" + x.name() + "' THEN " + x.value()).collect(Collectors.joining("\n")) +
            "\nELSE 0" +
            "\nEND" +
            "};\n\n";

    public static final String FILTER_FEEDS = """

            use ${CLUSTER_NAME};
            $WM_FEEDS = SELECT (domain, feed_url, type)
            FROM Concat(`${OFFER_FEEDS_MODERATION_TABLE}`,
                        `${OFFER_FEEDS_TABLE}`);

            INSERT INTO @intermediate
            SELECT domain, type, feed_url, offer_id, reason, comment, ts FROM ${SOURCE_TABLE}
            where (domain, feed_url, type) in $WM_FEEDS;

            COMMIT;

            """;

    public static final String PREFIX = GET_INT_TYPE_QUERY + GET_INT_REASON_QUERY + FILTER_FEEDS;

    public static final String DATA_SELECT_QUERY = """
            SELECT
                cast(${CURRENT_TIMESTAMP} * 1000 as Timestamp) as `time_insert`,
                cast(domain as Utf8) as `domain`,
                cast($get_int_type(type) as Int32) as `type`,
                cast(feed_url as Utf8) as `url`,
                cast(offer_id as Utf8) as `offer_id`,
                cast($get_int_reason(reason) as Int32) as `ban_reason`,
                cast(comment as Utf8) as `comment`,
                cast(ts * 1000 as Timestamp) as `ban_timestamp`,
            FROM @intermediate
            """;

    @Override
    public Result run(UUID runId) throws Exception {
        ytService.inTransaction(tablePath).execute(cypressService -> {
            YtNode node = cypressService.getNode(tablePath);
            if (node == null) {
                return false;
            }
            final DateTime modificationTime = new DateTime(node.getNodeMeta()
                    .get("modification_time")
                    .asText());
            CommonDataState settings = settingsService.getSettingUncached(LAST_BAN_OFFERS_IMPORT);
            if (settings != null && new DateTime(settings.getValue()).equals(modificationTime)) {
                return false;
            }
            StrSubstitutor substitutor = new StrSubstitutor(Map.of(
                    "CURRENT_TIMESTAMP", String.valueOf(modificationTime.getMillis()),
                    "SOURCE_TABLE", tablePath.toYqlPath(),
                    "OFFER_FEEDS_TABLE", offerFeedsPath.toYtPath(),
                    "OFFER_FEEDS_MODERATION_TABLE", offerFeedsModerationPath.toYtPath(),
                    "CLUSTER_NAME", tablePath.getCluster()
            ));
            ydbYqlService.importToYdb(feedsOfferBansYDao.getTablePath(), substitutor.replace(DATA_SELECT_QUERY), substitutor.replace(PREFIX));
            feedsOfferBansYDao.deleteBefore(modificationTime);
            settingsService.update(LAST_BAN_OFFERS_IMPORT, modificationTime.toString());
            return true;
        });
        return new Result(TaskResult.SUCCESS);
    }

    @Override
    public PeriodicTaskType getType() {
        return PeriodicTaskType.IMPORT_FEEDS_OFFER_BANS;
    }

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.startByCron("0 0/10 * * * *");
    }
}
