package com.bls.patronage.db.dao;

import com.bls.patronage.db.exception.DataAccessException;
import com.bls.patronage.db.mapper.DeckMapper;
import com.bls.patronage.db.mapper.DeckWithFlashcardsNumberMapper;
import com.bls.patronage.db.model.Deck;
import com.bls.patronage.db.model.DeckWithFlashcardsNumber;
import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.BindBean;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;

import java.util.Collection;
import java.util.List;
import java.util.UUID;

@RegisterMapper(DeckMapper.class)
public abstract class DeckDAO {

    @SqlQuery("select id, name, public from decks where id = :id")
    abstract Deck getDeck(@Bind("id") UUID id);

    @SqlQuery("select id, name, public from decks where name like :name")
    abstract List<Deck> getDecksUsingName(@Bind("name") String name);

    @SqlQuery("select id, name, public from decks")
    abstract Collection<Deck> getDecks();

    @SqlQuery("select decks.id, decks.name, decks.public from decks join usersDecks on usersDecks.deckId = decks.id " +
            "where usersDecks.userId = :userId group by decks.id")
    public abstract Collection<Deck> getAllUserDecks(@Bind("userId") UUID userId);

    @RegisterMapper(DeckWithFlashcardsNumberMapper.class)
    @SqlQuery("select decks.id, decks.name, decks.public, count(flashcards.question) as count " +
            "from decks " +
            "left join flashcards " +
            "on decks.id = flashcards.deckid " +
            "group by decks.id")
    public abstract Collection<DeckWithFlashcardsNumber> getAllDecksWithFlashcardsNumber();

    @RegisterMapper(DeckWithFlashcardsNumberMapper.class)
    @SqlQuery("select decks.id, decks.name, decks.public, count(flashcards.question) as count " +
            "from decks " +
            "left join flashcards " +
            "on decks.id = flashcards.deckid " +
            "inner join usersDecks on usersDecks.deckId = decks.id " +
            "where usersDecks.userId = :userId " +
            "group by decks.id")
    public abstract Collection<DeckWithFlashcardsNumber> getAllUserDecksWithFlashcardsNumber(
            @Bind("userId") UUID userId);

    @SqlUpdate("insert into decks (id, name, public) values (:id, :name, :isPublic)")
    abstract void insertDeck(@BindBean Deck deck);

    @SqlUpdate("insert into usersDecks (deckId, userId) values (:id, :userId)")
    abstract void insertUsersDeck(@BindBean Deck deck, @Bind("userId") UUID userId);

    @SqlUpdate("update decks set name = :name, public = :isPublic where id = :id")
    public abstract void update(@BindBean Deck deck);

    @SqlUpdate("delete from decks where id = :id")
    public abstract void deleteDeck(@Bind("id") UUID id);

    public void createDeck(Deck deck, UUID userId) {
        insertDeck(deck);
        insertUsersDeck(deck, userId);
    }

    public Deck getDeckById(UUID uuid) {
        Deck deck = getDeck(uuid);
        if (deck == null) {
            throw new DataAccessException("There is no deck with specified ID");
        }
        return deck;
    }

    public Collection<Deck> getDecksByName(String name) {
        List<Deck> decks = getDecksUsingName(name);
        if (decks.isEmpty()) {
            throw new DataAccessException("There are no decks matching this name");
        }
        return decks;
    }

    public Collection<Deck> getAllDecks(UUID userId) {
        Collection<Deck> decks = getDecks();
        decks.removeAll(getAllUserDecks(userId));
        return decks;
    }
}

@@ -711,1006 +711,253 @@
 ect 
-id, name, public from decks where id = :id%22)%0A    abstract Deck getDeck(@Bind(%22id%22) UUID id);%0A%0A    @SqlQuery(%22select id, name, public from decks where name like :name%22)%0A    abstract List%3CDeck%3E getDecksUsingName(@Bind(%22name%22) String name);%0A%0A    @SqlQuery(%22select id, name, public from decks%22)%0A    abstract Collection%3CDeck%3E getDecks();%0A%0A    @SqlQuery(%22select decks.id, decks.name, decks.public from decks join usersDecks on usersDecks.deckId = decks.id %22 +%0A            %22where usersDecks.userId = :userId group by decks.id%22)%0A    public abstract Collection%3CDeck%3E getAllUserDecks(@Bind(%22userId%22) UUID userId);%0A%0A    @RegisterMapper(DeckWithFlashcardsNumberMapper.class)%0A    @SqlQuery(%22select decks.id, decks.name, decks.public, count(flashcards.question) as count %22 +%0A            %22from decks %22 +%0A            %22left join flashcards %22 +%0A            %22on decks.id = flashcards.deckid %22 +%0A            %22group by decks.id%22)%0A    public abstract Collection%3CDeckWithFlashcardsNumber%3E getAllDecksWithFlashcardsNumber(
+decks.id, decks.name, decks.public from decks join usersDecks on usersDecks.deckId = decks.id %22 +%0A            %22where usersDecks.userId = :userId group by decks.id%22)%0A    public abstract Collection%3CDeck%3E getAllUserDecks(@Bind(%22userId%22) UUID userId
 );%0A%0A
@@ -2067,24 +2067,767 @@
  UUID id);%0A%0A
+    @SqlQuery(%22select id, name, public from decks where id = :id%22)%0A    abstract Deck getDeck(@Bind(%22id%22) UUID id);%0A%0A    @SqlQuery(%22select id, name, public from decks where name like :name%22)%0A    abstract List%3CDeck%3E getDecksUsingName(@Bind(%22name%22) String name);%0A%0A    @SqlQuery(%22select id, name, public from decks%22)%0A    abstract Collection%3CDeck%3E getDecks();%0A%0A    @RegisterMapper(DeckWithFlashcardsNumberMapper.class)%0A    @SqlQuery(%22select decks.id, decks.name, decks.public, count(flashcards.question) as count %22 +%0A            %22from decks %22 +%0A            %22left join flashcards %22 +%0A            %22on decks.id = flashcards.deckid %22 +%0A            %22group by decks.id%22)%0A    abstract Collection%3CDeckWithFlashcardsNumber%3E getDecksWithFlashcardsNumber();%0A%0A
     public v
@@ -3604,10 +3604,11 @@
 ;%0A    %7D%0A
+%0A
 %7D%0A

Rearrange code