package de.thpeetz.kontor.comics.services;

import static org.junit.jupiter.api.Assertions.*;

import java.util.List;

import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import de.thpeetz.kontor.comics.TestConstants;
import de.thpeetz.kontor.comics.data.Artist;
import de.thpeetz.kontor.comics.data.Comic;
import de.thpeetz.kontor.comics.data.ComicWork;
import de.thpeetz.kontor.comics.data.Issue;
import de.thpeetz.kontor.comics.data.Publisher;
import de.thpeetz.kontor.comics.data.StoryArc;
import de.thpeetz.kontor.comics.data.TradePaperback;
import de.thpeetz.kontor.comics.data.Volume;
import de.thpeetz.kontor.comics.data.Worktype;

@SpringBootTest
@TestMethodOrder(OrderAnnotation.class)
class ComicServiceTest {

    private static final Logger log = LoggerFactory.getLogger(ComicServiceTest.class);
    @Autowired
    private ComicService comicService;

    @Test
    @Order(1)
    void testFindAllArtists() {
        assertEquals(TestConstants.ARTIST_COUNT, comicService.findAllArtists(null).size());
        assertEquals(1, comicService.findAllArtists("Turn").size());
    }

    @Test
    @Order(1)
    void testFindArtistByName() {
        assertNull(comicService.findArtistByName("Lee, Stan"));
        Artist artist = comicService.findArtistByName("Turner, Michael");
        assertNotNull(artist);
        assertNotNull(artist.getComicWorks());
        assertFalse(artist.getComicWorks().isEmpty());
    }

    @Test
    @Order(2)
    void testSaveArtist() {
        Artist artist = new Artist();
        artist.setName(TestConstants.ARTIST_NAME);
        comicService.saveArtist(artist);
        assertEquals(TestConstants.ARTIST_COUNT + 1, comicService.findAllArtists(null).size());
    }

    @Test
    @Order(3)
    void testDeleteArtist() {
        List<Artist> artists = comicService.findAllArtists(TestConstants.ARTIST_NAME);
        assertEquals(1, artists.size());
        comicService.deleteArtist(artists.get(0));
        assertEquals(TestConstants.ARTIST_COUNT, comicService.findAllArtists(null).size());
    }

    @Test
    @Order(4)
    void testFindAllPublishers() {
        assertEquals(TestConstants.PUBLISHER_COUNT, comicService.findAllPublishers(null).size());
        assertEquals(1, comicService.findAllPublishers("Cow").size());
    }

    @Test
    @Order(4)
    void testFindPublisherByName() {
        Publisher publisher = comicService.findPublisherByName("Marvel");
        assertNotNull(publisher);
        assertNotNull(publisher.getComics());
        assertEquals(TestConstants.MARVEL_COMIC_COUNT, publisher.getComics().size());
        assertNull(comicService.findPublisherByName(TestConstants.PUBLISHER_NAME));
    }

    @Test
    @Order(5)
    void testSavePublisher() {
        Publisher publisher = new Publisher();
        publisher.setName(TestConstants.PUBLISHER_NAME);
        comicService.savePublisher(publisher);
        assertEquals(TestConstants.PUBLISHER_COUNT + 1, comicService.findAllPublishers(null).size());
    }

    @Test
    @Order(6)
    void testDeletePublisher() {
        List<Publisher> publishers = comicService.findAllPublishers(TestConstants.PUBLISHER_NAME);
        assertEquals(1, publishers.size());
        comicService.deletePublisher(publishers.get(0));
        assertEquals(TestConstants.PUBLISHER_COUNT, comicService.findAllPublishers(null).size());
    }

    @Test
    @Order(7)
    void testFindAllWorktypes() {
        assertEquals(TestConstants.WORKTYPE_COUNT, comicService.findAllWorktypes(null).size());
        assertEquals(1, comicService.findAllWorktypes("ite").size());
    }

    @Test
    @Order(7)
    void testFindWorktypeByName() {
        Worktype worktype = comicService.findWorktypeByName("Writer");
        assertNotNull(worktype);
        assertNotNull(worktype.getComicWorks());
        assertFalse(worktype.getComicWorks().isEmpty());
        worktype = comicService.findWorktypeByName("Inker");
        assertNotNull(worktype);
        assertNotNull(worktype.getComicWorks());
        assertTrue(worktype.getComicWorks().isEmpty());
        assertNull(comicService.findWorktypeByName(TestConstants.WORKTYPE_NAME));
    }

    @Test
    @Order(8)
    void testSaveWorktype() {
        Worktype worktype = new Worktype();
        worktype.setName(TestConstants.WORKTYPE_NAME);
        comicService.saveWorktype(worktype);
        assertEquals(TestConstants.WORKTYPE_COUNT + 1, comicService.findAllWorktypes(null).size());
    }

    @Test
    @Order(9)
    void testDeleteWorktype() {
        List<Worktype> worktypes = comicService.findAllWorktypes(TestConstants.WORKTYPE_NAME);
        assertEquals(1, worktypes.size());
        comicService.deleteWorktype(worktypes.get(0));
        assertEquals(TestConstants.WORKTYPE_COUNT, comicService.findAllWorktypes(null).size());
    }

    @Test
    @Order(10)
    void testFindComicByTitle() {
        assertNull(comicService.findComicByTitle(null));
        assertNotNull(comicService.findComicByTitle("Danger Girl"));
        assertNull(comicService.findComicByTitle("x-men"));
    }

    @Test
    @Order(11)
    void testSaveComic() {
        Publisher marvel = comicService.findAllPublishers("Marvel").get(0);
        Comic comic = new Comic();
        comic.setTitle(TestConstants.COMIC_TITLE);
        comic.setPublisher(marvel);
        comicService.saveComic(comic);
        assertEquals(TestConstants.COMIC_COUNT + 1, comicService.findAllComics(null).size());
    }

    @Test
    @Order(12)
    void testDeleteComic() {
        assertEquals(TestConstants.COMIC_COUNT + 1, comicService.findAllComics(null).size());
        List<Comic> comics = comicService.findAllComics(TestConstants.COMIC_TITLE);
        assertEquals(1, comics.size());
        Comic comic = comicService.findComicByTitle(TestConstants.COMIC_TITLE);
        assertNotNull(comic);
        comicService.deleteComic(comic);
        Publisher marvel = comicService.findPublisherByName("Marvel");
        assertNotNull(marvel.getComics());
        assertEquals(TestConstants.MARVEL_COMIC_COUNT, marvel.getComics().size());
        assertEquals(0, comicService.findAllComics(TestConstants.COMIC_TITLE).size());
        assertEquals(TestConstants.COMIC_COUNT, comicService.findAllComics(null).size());
    }

    @Test
    @Order(13)
    void testFindAllIssues() {
        assertEquals(TestConstants.ISSUE_COUNT, comicService.findAllIssues().size());
    }

    @Test
    @Order(14)
    void testFindAllIssuesForComic() {
        Comic comic = TestConstants.getComicWithIssues(comicService);
        List<Issue> issues = comicService.findAllIssuesForComic(comic);
        assertEquals(12, issues.size());
    }

    @Test
    @Order(15)
    void testSaveIssue() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        Issue issue = new Issue();
        issue.setComic(comic);
        issue.setIssueNumber(TestConstants.ISSUE_ISSUENUMBER);
        comicService.saveIssue(issue);
        assertEquals(TestConstants.ISSUE_COUNT + 1, comicService.findAllIssues().size());
        comic = TestConstants.getComicWithoutReferences(comicService);
        assertNotNull(comic.getIssues());
        assertEquals(1, comic.getIssues().size());
    }

    @Test
    @Order(16)
    void testDeleteIssue() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        List<Issue> issues = comicService.findAllIssuesForComic(comic);
        assertEquals(1, issues.size());
        comicService.deleteIssue(issues.get(0));
        assertEquals(TestConstants.ISSUE_COUNT, comicService.findAllIssues().size());
    }

    @Test
    @Order(17)
    void testFindAllTradePaperbacks() {
        assertEquals(TestConstants.TRADEPAPERBACK_COUNT, comicService.findAllTradePaperbacks(null).size());
        assertEquals(7, comicService.findAllTradePaperbacks("of").size());
    }

    @Test
    @Order(18)
    void testSaveTradePaperBack() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        TradePaperback tradePaperback = new TradePaperback();
        tradePaperback.setComic(comic);
        tradePaperback.setName(TestConstants.TRADEPAPERBACK_NAME);
        comicService.saveTradePaperBack(tradePaperback);
        assertEquals(TestConstants.TRADEPAPERBACK_COUNT + 1, comicService.findAllTradePaperbacks(null).size());
    }

    @Test
    @Order(19)
    void testDeleteTradePaperBack() {
        List<TradePaperback> tradePaperbacks = comicService.findAllTradePaperbacks(TestConstants.TRADEPAPERBACK_NAME);
        assertEquals(1, tradePaperbacks.size());
        comicService.deleteTradePaperBack(tradePaperbacks.get(0));
        assertEquals(TestConstants.TRADEPAPERBACK_COUNT, comicService.findAllTradePaperbacks(null).size());
    }

    @Test
    @Order(20)
    void testFindAllStoryArcs() {
        assertEquals(TestConstants.STORYARC_COUNT, comicService.findAllStoryArcs().size());
    }

    @Test
    @Order(21)
    void testFindAllStoryArcsForComic() {
        assertEquals(TestConstants.STORYARC_COUNT, comicService.findAllStoryArcsForComic(null).size());
        Comic comic = TestConstants.getComicWithStoryArcs(comicService);
        assertEquals(3, comicService.findAllStoryArcsForComic(comic).size());
    }

    @Test
    @Order(22)
    void testSaveStoryArc() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        StoryArc storyArc = new StoryArc();
        storyArc.setName(TestConstants.STORYARC_NAME);
        storyArc.setComic(comic);
        comicService.saveStoryArc(storyArc);
        assertEquals(TestConstants.STORYARC_COUNT + 1, comicService.findAllStoryArcs().size());
    }

    @Test
    @Order(23)
    void testDeleteStoryArc() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        List<StoryArc> storyArcs = comicService.findAllStoryArcsForComic(comic);
        assertEquals(1, storyArcs.size());
        comicService.deleteStoryArc(storyArcs.get(0));
        assertEquals(TestConstants.STORYARC_COUNT, comicService.findAllStoryArcs().size());
    }

    @Test
    @Order(24)
    void testFindAllVolumes() {
        assertEquals(TestConstants.VOLUME_COUNT, comicService.findAllVolumes().size());
    }

    @Test
    @Order(25)
    void testSaveVolume() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        Volume volume = new Volume();
        volume.setName(TestConstants.VOLUME_NAME);
        volume.setComic(comic);
        comicService.saveVolume(volume);
        assertEquals(TestConstants.VOLUME_COUNT + 1, comicService.findAllVolumes().size());
    }

    @Test
    @Order(26)
    void testFindAllVolumesForComic() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        List<Volume> volumes = comicService.findAllVolumesForComic(comic);
        assertEquals(1, volumes.size());
    }

    @Test
    @Order(27)
    void testDeleteVolume() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        List<Volume> volumes = comicService.findAllVolumesForComic(comic);
        comicService.deleteVolume(volumes.get(0));
        assertEquals(TestConstants.VOLUME_COUNT, comicService.findAllVolumes().size());
    }

    @Test
    @Order(28)
    void testFindAllComicWorks() {
        assertEquals(TestConstants.COMICWORK_COUNT, comicService.findAllComicWorks().size());
    }

    @Test
    @Order(29)
    void testSaveComicWork() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        Artist artist = TestConstants.getArtistWithoutReferences(comicService);
        Worktype worktype = TestConstants.getWorktypeWithoutReferences(comicService);
        ComicWork comicWork = new ComicWork();
        comicWork.setComic(comic);
        comicWork.setArtist(artist);
        comicWork.setWorkType(worktype);
        comicService.saveComicWork(comicWork);
        assertEquals(TestConstants.COMICWORK_COUNT + 1, comicService.findAllComicWorks().size());
    }

    @Test
    @Order(30)
    void testDeleteComicWork() {
        Comic comic = TestConstants.getComicWithoutReferences(comicService);
        Artist artist = TestConstants.getArtistWithoutReferences(comicService);
        Worktype worktype = TestConstants.getWorktypeWithoutReferences(comicService);
        List<ComicWork> comicWorks = comic.getComicWorks();
        assertNotNull(comicWorks);
        assertNotNull(artist.getComicWorks());
        assertNotNull(worktype.getComicWorks());
        assertEquals(1, comicWorks.size());
        assertEquals(1, artist.getComicWorks().size());
        assertEquals(1, worktype.getComicWorks().size());
        ComicWork comicWork = comicWorks.get(0);
        comicService.deleteComicWork(comicWork);
        assertEquals(TestConstants.COMICWORK_COUNT, comicService.findAllComicWorks().size());
    }
}
