package ru.yandex.webmaster3.storage.antispam.threats.dao;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.storage.user.UserTakeoutDataProvider;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;

@Repository
@Slf4j
public class HostThreatRecheckButtonStateYDao extends AbstractYDao implements UserTakeoutDataProvider {
    private static final String TABLE_NAME = "host_threat_recheck_button_state";
    private static final Duration DEFAULT_TTL = Duration.standardDays(7);

    @Autowired
    public HostThreatRecheckButtonStateYDao() {
        super(PREFIX_CHECKLIST, TABLE_NAME);
    }

    public void insertRecord(WebmasterHostId threatSourceHostId, String threat, DateTime recheckDate,
                             WebmasterHostId requestHost, long requestedByUser, Duration ttl) {
        execute(
                upsert(
                        F.THREAT_SOURCE_HOST_ID.value(threatSourceHostId),
                        F.THREAT.value(threat),
                        F.RECHECK_DATE.value(recheckDate),
                        F.REQUEST_HOST_ID.value(requestHost),
                        F.REQUEST_USER_ID.value(requestedByUser),
                        F.EXPIRE_AFTER.value(DateTime.now().plus(ttl == null ? DEFAULT_TTL : ttl))
                )
        );
    }

    public void deleteForUser(long userId) {
        delete().where(F.REQUEST_USER_ID.eq(userId)).execute();
    }

    public Map<String, DateTime> getRecordsForHost(WebmasterHostId hostId, Set<String> threats) {
        var st = select(F.THREAT.combine(F.RECHECK_DATE, Pair::of))
                .where(F.THREAT_SOURCE_HOST_ID.eq(hostId))
                .and(F.EXPIRE_AFTER.gt(DateTime.now()))
                .and(F.THREAT.in(threats));
        return queryForList(
                st.getStatement(),
                DataMapper.create(F.THREAT, F.RECHECK_DATE, Pair::of)
        ).stream().collect(Collectors.toMap(Pair::getLeft, Pair::getRight));
    }

    @Override
    public void deleteUserData(WebmasterUser user) {
        deleteForUser(user.getUserId());
    }

    @Override
    public @NotNull List<String> getTakeoutTables() {
        return List.of(
                getTablePath()
        );
    }

    private static class F {
        static final Field<WebmasterHostId> THREAT_SOURCE_HOST_ID = Fields.hostIdField("threat_source_host_id");
        static final Field<String> THREAT = Fields.stringField("threat");
        static final Field<DateTime> RECHECK_DATE = Fields.jodaDateTimeField("recheck_date");
        static final Field<WebmasterHostId> REQUEST_HOST_ID = Fields.hostIdField("request_host_id");
        static final Field<Long> REQUEST_USER_ID = Fields.longField("request_user_id");
        static final Field<DateTime> EXPIRE_AFTER = Fields.jodaDateTimeField("expire_after");
    }
}

