package ru.yandex.webmaster3.storage.nca;

import java.util.List;
import java.util.stream.Stream;

import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.util.PageUtils;
import ru.yandex.webmaster3.storage.nca.data.CertificateIdByDomainEntry;
import ru.yandex.webmaster3.storage.nca.data.LogEntryType;
import ru.yandex.webmaster3.storage.util.clickhouse2.SimpleByteArrayOutputStream;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.Or;
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.Statement;

@Slf4j
@Repository
public class CertificateIdByDomainCHDao extends AbstractCtlogCertificatesCHDao<CertificateIdByDomainCHDao.Row> {
    private static final String DB_NAME = DB_WEBMASTER3;
    private static final String SHARD_TABLE = "certificate_id_by_domain";

    public Statement getCertificateIdsByDomain(String reversedDomain, List<String> domainsForCheck,
                                               PageUtils.Pager pager) {
        Or statement = QueryBuilder.selectDistinct(F.SERIES_NUMBER, F.NOT_BEFORE, F.TYPE)
                .from(DB_NAME, SHARD_TABLE)
                .prewhere(QueryBuilder.in(F.REVERSED_DOMAIN, domainsForCheck))
                .or(QueryBuilder.startsWith(F.REVERSED_DOMAIN, reversedDomain + "."));
        if (pager != null) {
            statement.orderBy(F.NOT_BEFORE, OrderBy.Direction.DESC)
                    .limit(pager.toRangeStart(), pager.getPageSize());
        }
        return statement;
    }

    public Statement getCertificateIdsByDomainCount(String reversedDomain, List<String> domainsForCheck) {
        Statement statement = QueryBuilder.selectDistinct(F.SERIES_NUMBER, F.NOT_BEFORE, F.TYPE)
                .from(DB_NAME, SHARD_TABLE)
                .prewhere(QueryBuilder.in(F.REVERSED_DOMAIN, domainsForCheck))
                .or(QueryBuilder.startsWith(F.REVERSED_DOMAIN, reversedDomain + "."));
        return QueryBuilder.select(QueryBuilder.count().toString()).from(statement);
    }


    @Override
    protected SimpleByteArrayOutputStream packRow(SimpleByteArrayOutputStream bs, Row row) {
        return packRowValues(bs,
                row.getReversedDomain(),
                row.getCtlog(),
                row.getCtlogRow(),
                row.getSerialNumber(),
                row.getNotBefore(),
                row.getType().value()
        );
    }

    @Override
    protected int getShard(Row row) {
        return getShardByReversedSecondLevelDomain(row.getReversedDomain());
    }

    // берем шард по домену второго уровня
    protected int getShardByReversedSecondLevelDomain(String reversedDomain) {
        String[] split = reversedDomain.split("\\.");
        String newDomain = split[0] + "." + split[1];
        return super.getShard(newDomain);
    }

    @Override
    protected Stream<Row> rowFromEntry(CertificateIdByDomainEntry entry) {
        return entry.getDomains().stream().map(domain -> {
            return new Row(
                    NcaRulesService.reverseDomain(domain),
                    entry.getCtlog(),
                    entry.getCtlogRow(),
                    entry.getNotBefore(),
                    entry.getSerialNumber(),
                    entry.getLogEntryType()
            );
        });
    }

    @Override
    public String getDbName() {
        return DB_NAME;
    }

    @Override
    public String getTableName() {
        return SHARD_TABLE;
    }

    @Override
    public String[] getInsertFields() {
        return INSERT_FIELDS;
    }

    @Value
    public static class Row {
        String reversedDomain;
        String ctlog;
        int ctlogRow;
        long notBefore;
        String serialNumber;
        LogEntryType type;
    }

    private static final String[] INSERT_FIELDS = {F.REVERSED_DOMAIN, F.CTLOG, F.CTLOG_ROW, F.SERIES_NUMBER,
            F.NOT_BEFORE, F.TYPE};


}
