package ru.yandex.canvas.repository;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.mongodb.MongoBulkWriteException;
import com.mongodb.bulk.BulkWriteError;
import org.bson.types.ObjectId;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoOperations;

import ru.yandex.canvas.model.video.Addition;

public class RepositoryUtils {

    /*
       Standard insert stops on first error, though it's hard to find (without another request) which objects had been failed.
       BulkOperation in _unordered_ mode continues on errors and returns indexes of bad objects
     */

    public static <T extends Addition> List<T> insertWithDups(List<T> additions, MongoOperations mongoOperations, Class<? extends T> clazz) {
        if (additions.size() == 0) {
            return Collections.emptyList();
        }

        for (Addition addition : additions) {
            if (addition.getId() == null) {
                addition.setId(new ObjectId().toString());
            }
        }

        BulkOperations bulkOperations = mongoOperations.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz);

        bulkOperations.insert(additions);

        List<T> failed = new ArrayList<>();

        try {
            bulkOperations.execute();
        } catch (DuplicateKeyException e) {
            for (BulkWriteError error : ((MongoBulkWriteException) e.getCause()).getWriteErrors()) {
                if (error.getCode() != 11000) { //DuplicateKey code
                    throw e;
                }

                failed.add(additions.get(error.getIndex()));
            }
        }

        return failed;
    }

    // we have preset_id of both types in mongodb (bloody hell!) - string and integer. So we have to search
    // through all types
    public static Object[] presetIdsToSearch(List<Long> presetIds) {
        Object[] converted = new Object[presetIds.size() * 2];

        for (int i = 0; i < presetIds.size(); i++) {
            converted[2 * i] = presetIds.get(i);
            converted[2 * i + 1] = presetIds.get(i).toString();
        }

        return converted;
    }
}
