package ru.yandex.webmaster3.storage.host.moderation.camelcase.dao;

import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.storage.host.moderation.camelcase.DisplayNameRequest;
import ru.yandex.webmaster3.storage.host.moderation.camelcase.HostDisplayNameModerationRequestState;
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 javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;

/**
 * @author leonidrom
 */
@Repository
public class HostModeratedDisplayNameYDao extends AbstractYDao {
    private static final String TABLE_NAME = "host_moderated_display_name";

    public HostModeratedDisplayNameYDao() {
        super(PREFIX_HOST, TABLE_NAME);
    }

    @Nullable
    public DisplayNameRequest getLastRequest(WebmasterHostId hostId) {
        return select(MAPPER)
                .where(F.HOST_ID.eq(hostId))
                .order(F.CREATION_DATE.desc())
                .limit(1)
                .queryOne();
    }

    public void forEach(Consumer<DisplayNameRequest> consumer) {
        streamReader(MAPPER, consumer);
    }

    public void saveRequest(DisplayNameRequest request) {
        upsert(
                F.HOST_ID.value(request.getHostId()),
                F.REQUEST_ID.value(request.getRequestId()),
                F.DISPLAY_NAME.value(request.getDisplayName()),
                F.CREATION_DATE.value(request.getCreationDate()),
                F.IS_CLOSED.value(request.isClosed()))
                .execute();
    }

    public void saveBatch(List<DisplayNameRequest> batch) {
        batchUpdate(UPDATE_VALUE_MAPPER, batch).execute();
    }

    public void closeRequest(DisplayNameRequest request) {
        update()
                .with(F.IS_CLOSED.set(true))
                .where(F.HOST_ID.eq(request.getHostId()))
                .execute();
    }

    private static final class F {
        static final Field<WebmasterHostId> HOST_ID = Fields.hostIdField("host_id");
        static final Field<UUID> REQUEST_ID = Fields.uuidField("request_id");
        static final Field<String> DISPLAY_NAME = Fields.stringField("display_name");
        static final Field<DateTime> CREATION_DATE = Fields.jodaDateTimeField("creation_date");
        static final Field<Boolean> IS_CLOSED = Fields.boolField("is_closed");
    }

    private static final DataMapper<DisplayNameRequest> MAPPER = DataMapper.create(
            F.HOST_ID, F.REQUEST_ID, F.DISPLAY_NAME, F.CREATION_DATE, F.IS_CLOSED,
            (hostId, requestId, displayName, creationDate, isClosed) -> {
                return DisplayNameRequest.builder()
                        .hostId(hostId)
                        .requestId(requestId)
                        .displayName(displayName)
                        .state(HostDisplayNameModerationRequestState.ACCEPTED)
                        .creationDate(creationDate)
                        .modificationDate(creationDate)
                        .isUserClosedInfoBanner(false)
                        .userId(null)
                        .assessorId(null)
                        .isClosed(isClosed)
                        .build();
            }
    );

    private static final ValueDataMapper<DisplayNameRequest> UPDATE_VALUE_MAPPER = ValueDataMapper.create(
            Pair.of(F.HOST_ID, r -> F.HOST_ID.get(r.getHostId())),
            Pair.of(F.REQUEST_ID, r -> F.REQUEST_ID.get(r.getRequestId())),
            Pair.of(F.DISPLAY_NAME, r -> F.DISPLAY_NAME.get(r.getDisplayName())),
            Pair.of(F.CREATION_DATE, r -> F.CREATION_DATE.get(r.getCreationDate())),
            Pair.of(F.IS_CLOSED, r -> F.IS_CLOSED.get(r.isClosed()))
    );
}
