package com.example.backend;

import java.util.Map;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import com.example.backend.categories.model.CategoryEntity;
import com.example.backend.categories.service.CategoryService;
import com.example.backend.books.model.BookEntity;
import com.example.backend.books.service.BookService;
import com.example.backend.orders.model.OrderEntity;
import com.example.backend.orders.service.OrderService;
import com.example.backend.users.model.UserEntity;
import com.example.backend.users.service.UserService;
import com.example.backend.core.error.NotFoundException;

@SpringBootTest
class OrderServiceTests {
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BookService bookService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderService orderService;

    private OrderEntity order;

    private UserEntity user;

    private BookEntity book1;
    private BookEntity book2;
    private BookEntity book3;

    @BeforeEach
    void createData() {
        removeData();

        final var category = categoryService.create(new CategoryEntity("Фэнтези"));
        book1 = bookService.create(new BookEntity(category, "Шестерка воронов", "Ли Бардуго",
                700.00,
                "Триша Левенселлер — американская писательница, подарившая вам роман «Тени между нами», который стал бестселлером Amazon в разделе «Фэнтези YA», вновь радует своих фанатов новой магической историей «Клинок тайн».\n\nЕще до выхода в свет книгу добавили в раздел «Хочу прочитать» более 10 тысяч человек на портале Goodreads.com.\n\n«Клинок тайн» — первая часть захватывающей дилогии про девушку, которая благодаря магии крови создает самое опасное в мире оружие, и ослепительного юношу, что составляет ей компанию в этом непростом приключении.",
                "Юная Зива предпочитает проводить время с оружием, а не с людьми. Она кузнец и ей предстоит создать самое могущественное оружие на земле.\n\nДевушка демонстрирует меч, способный от одной капли крови врага раскрыть все тайные замыслы его обладателю.\n\nОднако у заказчика на оружие другие планы: заставить Зиву вооружить мечами свое войско и поработить весь мир. Когда девушка понимает, что меч, созданный благодаря магии крови, невозможно уничтожить и рано или поздно на нее объявят охоту, ей остается только одно – бежать, не оглядываясь. Зиве теперь суждено спасти мир от собственного творения. Но как бы далеко она ни старалась убежать, все ловушки уже расставлены.",
                "2946447", "Эксмо", "Young Adult. Бестселлеры Триши Левенселлер", 2022, 480, "20.7x13x2.5",
                "Мягкий переплёт", 1500, 440, ""));
        book2 = bookService.create(new BookEntity(category, "Форсайт", "Сергей Лукъяненко", 775.00,
                "Новый долгожданный роман от автора бестселлеров «Ночной дозор» и «Черновик». Увлекательная история о Мире После и мире настоящего, где 5 процентов людей знают о надвигающемся апокалипсисе больше, чем кто-либо может представить.",
                "Людям порой снится прошлое. Иногда хорошее, иногда не очень. Но что делать, если тебе начинает сниться будущее? И в нём ничего хорошего нет совсем.",
                "3001249", "АСТ", "Книги Сергея Лукьяненко", 2023, 352, "20.5x13x2", "Твердый переплёт", 20000,
                350, ""));
        book3 = bookService.create(new BookEntity(category,
                "Колесо Времени. Книга 11. Нож сновидений",
                "Роберт Джордан", 977.00,
                "Последняя битва не за горами. Об этом говорят знамения, повсеместно наблюдаемые людьми: на улицах городов и сел появляются ходячие мертвецы, они больше не в состоянии покоиться в земле с миром; восстают из небытия города и исчезают на глазах у людей… Все это знак того, что истончается окружающая реальность и укрепляется могущество Темного. Так говорят древние предсказания. Ранд ал’Тор, Дракон Возрожденный, скрывается в отдаленном поместье, чтобы опасность, ему грозящая, не коснулась кого-нибудь еще. Убежденный, что для Последней битвы нужно собрать как можно большее войско, он наконец решает заключить с явившимися из-за океана шончан жизненно необходимое перемирие. Илэйн, осажденная в Кэймлине, обороняет город от войск Аримиллы, претендующей на андорский трон, и одновременно ведет переговоры с представителями других знатных Домов. Эгвейн, возведенную на Престол Амерлин мятежными Айз Седай и схваченную в результате предательства, доставляют в Тар Валон, в Белую Башню. А сам лагерь противников Элайды взбудоражен таинственными убийствами, совершенными посредством Единой Силы… В настоящем издании текст романа заново отредактирован и исправлен.",
                "", "3009341", "Азбука", "Звезды новой фэнтези", 2023, 896,
                "21.5x14.4x4.1", "Твердый переплёт", 8000, 1020, ""));
        user = userService
                .create(new UserEntity("admin", "forum98761@gmail.com", "bth4323", "Александр", "Мельников"));
        order = orderService
                .create(user.getId(), new OrderEntity(),
                        Map.of(book1.getId(), 3, book2.getId(), 1, book3.getId(), 2));
        orderService
                .create(user.getId(),
                        new OrderEntity(),
                        Map.of(book1.getId(), 5));
        orderService
                .create(user.getId(),
                        new OrderEntity(),
                        Map.of(book2.getId(), 1, book3.getId(), 1));
    }

    @AfterEach
    void removeData() {
        userService.getAll().forEach(item -> userService.delete(item.getId()));
        bookService.getAll(0L).forEach(item -> bookService.delete(item.getId()));
        categoryService.getAll().forEach(item -> categoryService.delete(item.getId()));
    }

    @Test
    void getTest() {
        Assertions.assertThrows(NotFoundException.class, () -> orderService.get(user.getId(), 0L));
    }

    @Transactional
    @Test
    void createTest() {
        Assertions.assertEquals(3, orderService.getAll(user.getId()).size());
        Assertions.assertEquals(order, orderService.get(user.getId(), order.getId()));
    }

    @Test
    void deleteTest() {
        orderService.delete(user.getId(), order.getId());
        Assertions.assertEquals(2, orderService.getAll(user.getId()).size());

        final OrderEntity newEntity = orderService.create(user.getId(),
                new OrderEntity(),
                Map.of(book1.getId(), 3, book2.getId(), 1, book3.getId(), 2));
        Assertions.assertEquals(3, orderService.getAll(user.getId()).size());
        Assertions.assertNotEquals(order.getId(), newEntity.getId());
    }

    @Test
    void getSumTest() {
        Double sum = orderService.getSum(user.getId(), order.getId());
        Assertions.assertEquals(book1.getPrice() * 3 + book2.getPrice() + book3.getPrice() * 2, sum);
    }

    @Test
    void getFullCountTest() {
        Integer count = orderService.getFullCount(user.getId(), order.getId());
        Assertions.assertEquals(6, count);
    }

    @Transactional
    @Test
    void getOrderBooksTest() {
        Assertions.assertEquals(3, orderService.getOrderBooks(user.getId(), order.getId()).size());
    }
}
