package ru.yandex.webmaster3.storage.niche;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.searchquery.OrderDirection;
import ru.yandex.webmaster3.core.util.FNVHash;
import ru.yandex.webmaster3.storage.searchquery.DeviceType;
import ru.yandex.webmaster3.storage.searchquery.RegionInclusion;
import ru.yandex.webmaster3.storage.searchquery.dao.QueryStatisticsFiltersService;
import ru.yandex.webmaster3.storage.util.clickhouse2.AbstractClickhouseDao;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseQueryContext;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.GroupableLimitableOrderable;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.OrderBy;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.QueryBuilder;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.RawStatement;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.Statement;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.Where;

/**
 * ishalaru
 * 28.06.2021
 **/
@Repository
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class NicheQueriesCHDao extends AbstractClickhouseDao {
    public static final String TABLE_NAME = "queries3";

    private final QueryStatisticsFiltersService mdbQueryStatisticsFiltersService;

    public List<Pair<String, Long>> getQueries(WebmasterHostId hostId, LocalDate dateFrom, LocalDate dateTo,
                                               Integer[] regionId, DeviceType deviceType, QuerySource source,
                                               SortField orderBy, OrderDirection orderDirection, int limit, int offset) {
        Where query = QueryBuilder.select(F.QUERY, "sum(" + F.COUNT + ") as " + F.COUNT + "_sum")
                .from(AbstractClickhouseDao.DB_WEBMASTER3_NICHE, TABLE_NAME)
                .where(QueryBuilder.eq(F.HOST_ID, hostId))
                .and(QueryBuilder.gte(F.DATE, dateFrom))
                .and(QueryBuilder.lte(F.DATE, dateTo))
                .and(getDeviceFilter(deviceType))
                .and(source.getQueryFilter(F.SOURCE_FLAG))
                .and(new RawStatement(mdbQueryStatisticsFiltersService.getRegionFilter(RegionInclusion.INCLUDE_ALL, regionId)));
        GroupableLimitableOrderable fst = query.groupBy(F.QUERY).orderBy(orderBy.field,
                orderDirection == OrderDirection.ASC ? OrderBy.Direction.ASC : OrderBy.Direction.DESC)
                .limit(offset,limit);
        return getClickhouseServer().queryAll(chContext(hostId), fst.toString(),
                r -> Pair.of(r.getString(F.QUERY), r.getLongUnsafe(F.COUNT + "_sum")));
    }

    public long countQueries(WebmasterHostId hostId,
                             LocalDate dateFrom, LocalDate dateTo,
                             Integer[] regionId,
                             DeviceType deviceType,
                             QuerySource source) {
        Where query = QueryBuilder.select(F.QUERY)
                .from(AbstractClickhouseDao.DB_WEBMASTER3_NICHE, TABLE_NAME)
                .where(QueryBuilder.eq(F.HOST_ID, hostId))
                .and(QueryBuilder.gte(F.DATE, dateFrom))
                .and(QueryBuilder.lte(F.DATE, dateTo))
                .and(getDeviceFilter(deviceType))
                .and(source == null ? QueryBuilder.trueCondition() : source.getQueryFilter(F.SOURCE_FLAG))
                .and(new RawStatement(mdbQueryStatisticsFiltersService.getRegionFilter(RegionInclusion.INCLUDE_ALL, regionId)));
        GroupableLimitableOrderable fst = query.groupBy(F.QUERY);
        return getClickhouseServer().queryOne(chContext(hostId), QueryBuilder.select(QueryBuilder.count().toString()).from(fst).toString(),
                r -> r.getLongUnsafe(0)).orElse(0L);
    }



    // TODO злобный костыль, убрать после UX
    private static Statement getDeviceFilter(DeviceType deviceType) {
        if (deviceType == DeviceType.MOBILE) {
            deviceType = DeviceType.PAD;
        } else if (deviceType == null) {
            deviceType = DeviceType.ALL_DEVICES;
        }
        return deviceType.getQueryFilter();
    }

    private ClickhouseQueryContext.Builder chContext(WebmasterHostId hostId) {
        int shardsCount = getClickhouseServer().getShardsCount();
        int shard = (int) FNVHash.hash64Mod(hostId.toString(), shardsCount);
        return ClickhouseQueryContext.useDefaults().setHost(getClickhouseServer().pickAliveHostOrFail(shard));
    }

    @AllArgsConstructor
    public enum SortField {
        QUERY(F.QUERY),
        COUNT(F.COUNT + "_sum"),
        ;

        private final String field;
    }


    public interface F {
        String DATE = "date";
        String HOST_ID = "host_id";
        String QUERY = "query";
        String REGION_ID = "region_id";
        String DEVICE_TYPE = "device_type";
        String COUNT = "count";
        String SOURCE_FLAG = "source";
        String SHARE = "share";
    }
}
