package com.atlassian.stash.internal.notification.batch.dao;

import com.atlassian.activeobjects.external.ActiveObjects;
import com.atlassian.bitbucket.ao.AbstractAoDao;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;

import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;

public class AoUserNotificationDao extends AbstractAoDao implements UserNotificationDao {

    static final int MAX_IN_PARAMS = 500;

    public AoUserNotificationDao(ActiveObjects ao) {
        super(ao);
    }

    @Override
    @Nonnull
    public UserNotification create(int userId, @Nonnull Date date, @Nonnull String batchSenderId,
                                   @Nonnull String batchId, @Nonnull String data) {
        return ao.create(AoUserNotification.class, ImmutableMap.<String, Object>of(
                AoUserNotification.USER_ID_COLUMN, userId,
                AoUserNotification.TIMESTAMP_COLUMN, checkNotNull(date, "date"),
                AoUserNotification.BATCH_SENDER_ID_COLUMN, checkNotNull(batchSenderId, "batchSenderId"),
                AoUserNotification.BATCH_ID_COLUMN, checkNotNull(batchId, "batchId"),
                AoUserNotification.DATA_COLUMN, checkNotNull(data, "data")
        ));
    }

    @Override
    @Nonnull
    public Iterable<UserNotification> findAll() {
        return Arrays.<UserNotification>asList(ao.find(AoUserNotification.class));
    }

    @Override
    public int count() {
        return ao.count(AoUserNotification.class);
    }

    @Override
    public void delete(@Nonnull Iterable<Long> ids) {
        // Some databases have a limit on the number of expressions an SQL "IN" list can contain, so split them up.
        Iterable<List<Long>> groupedIds = Iterables.partition(ids, MAX_IN_PARAMS);
        for (List<Long> idGroup : groupedIds) {
            deleteIds(idGroup);
        }
    }

    private void deleteIds(List<Long> ids) {
        Iterable<String> params = Iterables.transform(ids, Functions.constant("?"));
        String criteria = getIdInCriteria(params);
        ao.deleteWithSQL(AoUserNotification.class, criteria, ids.toArray());
    }

    private String getIdInCriteria(Iterable<String> input) {
        String params = Joiner.on(",").join(input);
        return AoUserNotification.ID_COLUMN + " in (" + params + ")";
    }

}
