package ru.yandex.webmaster3.storage.sitemap.dao;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.sitemap.UserSitemap;
import ru.yandex.webmaster3.core.sitemap.UserSitemapStatus;
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;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.ValueDataMapper;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;

/**
 * @author aherman
 */
@Repository
public class UserAddedSitemapYDao extends AbstractYDao {
    public UserAddedSitemapYDao() {
        super(PREFIX_SITEMAP, "user_added_sitemaps");
    }

    private static final ValueDataMapper<UserSitemap> INSERT_VALUE_MAPPER = ValueDataMapper.create2(
            Pair.of(F.HOST_ID, UserSitemap::getHostId),
            Pair.of(F.SITEMAP_ID, UserSitemap::getSitemapId),
            Pair.of(F.SITEMAP_URL, UserSitemap::getSitemapUrl),
            Pair.of(F.ADD_DATE, UserSitemap::getAddDate),
            Pair.of(F.DELETED, UserSitemap::isDeleted),
            Pair.of(F.DELETE_DATE, UserSitemap::getDeleteDate),
            Pair.of(F.STATUS, UserSitemap::getStatus)
    );

    public void addSitemaps(Collection<UserSitemap> userSitemaps) {
        batchInsert(INSERT_VALUE_MAPPER, userSitemaps).execute();
    }

    public void addSitemap(UserSitemap userSitemap) {
        addSitemaps(Collections.singleton(userSitemap));
    }

    public void markDeleted(WebmasterHostId hostId, UUID sitemapId) {
        update().with(F.DELETED.set(true))
                .and(F.DELETE_DATE.set(DateTime.now()))
                .where(F.HOST_ID.eq(hostId))
                .and(F.SITEMAP_ID.eq(sitemapId))
                .execute();
    }

    public UserSitemap getSitemap(WebmasterHostId hostId, UUID sitemapId) {
        return select(MAPPER).where(F.HOST_ID.eq(hostId)).and(F.SITEMAP_ID.eq(sitemapId)).queryOne();
    }

    public List<UserSitemap> listSitemaps(WebmasterHostId hostId) {
        return select(MAPPER).where(F.HOST_ID.eq(hostId)).queryForList();
    }

    public void forEach(Consumer<Triple<WebmasterHostId, String, Boolean>> consumer) {
        streamReader(TRIPLE_MAPPER, consumer);
    }

    private static final DataMapper<UserSitemap> MAPPER = DataMapper.create(F.HOST_ID, F.SITEMAP_URL, F.SITEMAP_ID, F.ADD_DATE,
            F.DELETED, F.DELETE_DATE, F.STATUS, UserSitemap::new);

    private static final DataMapper<Triple<WebmasterHostId, String, Boolean>> TRIPLE_MAPPER = DataMapper.create(F.HOST_ID,
            F.SITEMAP_URL,
            F.DELETED,
            Triple::of);

    private interface F {
        Field<WebmasterHostId> HOST_ID = Fields.hostIdField("host_id");
        Field<UUID> SITEMAP_ID = Fields.uuidField("sitemap_id");
        Field<String> SITEMAP_URL = Fields.stringField("sitemap_url");
        Field<DateTime> ADD_DATE = Fields.jodaDateTimeField("add_date");
        Field<Boolean> DELETED = Fields.boolField("deleted");
        Field<DateTime> DELETE_DATE = Fields.jodaDateTimeField("delete_date").makeOptional();
        Field<UserSitemapStatus> STATUS = Fields.stringEnumField("status", UserSitemapStatus.R);
    }
}
