package ru.yandex.webmaster3.storage.turbo.dao.adv;

import java.util.Map;
import java.util.function.Consumer;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.util.enums.EnumResolver;
import ru.yandex.webmaster3.core.turbo.model.advertising.AdvertisingPlacement;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.storage.turbo.service.adv.AutoAdvStatus;
import ru.yandex.webmaster3.storage.turbo.service.adv.TurboAdvStatus;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.Update;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.Upsert;
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;

/**
 * ishalaru
 * 01.09.2020
 **/
@Slf4j
@Repository
public class TurboAutoAdvYDao extends AbstractYDao {
    private static final String TABLE_NAME = "turbo_auto_adv";

    public TurboAutoAdvYDao() {
        super(PREFIX_TURBO, TABLE_NAME);
    }

    public void save(String domain, InformationBlock blocks, AutoAdvStatus status, TurboAdvStatus turboAdvStatus, DateTime createDate) {
        final Upsert upsert = upsert(F.DOMAIN.value(domain),
                F.ADV_INFO.value(JsonMapping.writeValueAsString(blocks)),
                F.STATUS.value(status),
                F.TURBO_ADV_STATUS.value(turboAdvStatus),
                F.UPDATE_DATE.value(createDate));
        execute(upsert);
    }

    public InformationBlock loadBlock(String domain) {
        final String s = queryOne(select(F.ADV_INFO)
                .where(F.DOMAIN.eq(domain)).getStatement(), BLOCKS);
        if (s != null) {
            return JsonMapping.readValue(s, InformationBlock.class);
        }
        return null;

    }

    public void delete(String domain) {
        execute(delete().where(F.DOMAIN.eq(domain)).getStatement());
    }

    public void updateStatus(String domain, AutoAdvStatus status) {
        final Update statement = update(F.STATUS.set(status), F.UPDATE_DATE.set(DateTime.now()))
                .where(F.DOMAIN.eq(domain)).getStatement();
        execute(statement);
    }

    public Pair<AutoAdvStatus, TurboAdvStatus> loadStatus(String domain) {
        return queryOne(select(STATUS).where(F.DOMAIN.eq(domain)).getStatement(), STATUS);
    }

    public void forEach(Consumer<Record> consumer) {
        streamReader(RECORD, consumer);
    }

    static final DataMapper<Pair<AutoAdvStatus, TurboAdvStatus>> STATUS = DataMapper.create(F.STATUS, F.TURBO_ADV_STATUS, Pair::of);
    static final DataMapper<String> BLOCKS = DataMapper.create(F.ADV_INFO, (blocks) -> blocks);
    static final DataMapper<Record> RECORD = DataMapper.create(F.DOMAIN, F.ADV_INFO, F.STATUS, F.TURBO_ADV_STATUS, F.UPDATE_DATE, Record::new);

    public interface F {
        Field<String> DOMAIN = Fields.stringField("domain");
        Field<String> ADV_INFO = Fields.stringField("info");
        Field<AutoAdvStatus> STATUS = Fields.stringEnumField("status", EnumResolver.er(AutoAdvStatus.class));
        Field<TurboAdvStatus> TURBO_ADV_STATUS = Fields.stringEnumField("adv_status", EnumResolver.er(TurboAdvStatus.class));
        Field<DateTime> UPDATE_DATE = Fields.jodaDateTimeField("updated");

    }

    @Value
    public static class Record {
        String domain;
        String info;
        AutoAdvStatus status;
        TurboAdvStatus advStatus;
        DateTime updateDate;
    }

    // сейчас делаем блоки только для turbo touch, когда понадобиться расширим данный класс
    @Value
    public static class InformationBlock {
        public final static TypeReference<InformationBlock> TYPE_REFERENCE = new TypeReference<>() {
        };

        @JsonProperty("block")
        Map<AdvertisingPlacement, String> blocks;
    }
}
