package app.mealsmadeeasy.api.recipe.star;

import app.mealsmadeeasy.api.PostgresTestsExtension;
import app.mealsmadeeasy.api.recipe.Recipe;
import app.mealsmadeeasy.api.recipe.RecipeService;
import app.mealsmadeeasy.api.recipe.spec.RecipeCreateSpec;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserCreateException;
import app.mealsmadeeasy.api.user.UserService;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.UUID;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@ExtendWith(PostgresTestsExtension.class)
public class RecipeStarServiceTests {

    @Autowired
    private RecipeStarService recipeStarService;

    @Autowired
    private UserService userService;

    @Autowired
    private RecipeService recipeService;

    private User seedUser() {
        final String uuid = UUID.randomUUID().toString();
        try {
            return this.userService.createUser(uuid, uuid + "@test.com", "test");
        } catch (UserCreateException e) {
            throw new RuntimeException(e);
        }
    }

    private Recipe seedRecipe(User owner) {
        final RecipeCreateSpec spec = RecipeCreateSpec.builder()
                .slug(UUID.randomUUID().toString())
                .title("Test Recipe")
                .rawText("My great recipe has five ingredients.")
                .isPublic(true)
                .build();
        return this.recipeService.create(owner, spec, false);
    }

    @Test
    public void createViaUsernameAndSlug() {
        final User owner = this.seedUser();
        final User starer = this.seedUser();
        final Recipe recipe = this.seedRecipe(owner);
        final RecipeStar star = assertDoesNotThrow(() -> this.recipeStarService.create(
                recipe.getOwner().getUsername(),
                recipe.getSlug(),
                starer
        ));
        assertThat(star.getTimestamp(), is(notNullValue()));
    }

    @Test
    public void createViaId() {
        final User owner = this.seedUser();
        final User starer = this.seedUser();
        final Recipe recipe = this.seedRecipe(owner);
        final RecipeStar star = assertDoesNotThrow(() -> this.recipeStarService.create(
                recipe.getId(),
                starer.getId()
        ));
        assertThat(star.getTimestamp(), is(notNullValue()));
    }

    @Test
    public void find() {
        final User owner = this.seedUser();
        final User starer = this.seedUser();
        final Recipe recipe = this.seedRecipe(owner);
        this.recipeStarService.create(recipe.getId(), starer.getId());
        final @Nullable RecipeStar star = this.recipeStarService.find(
                recipe.getOwner().getUsername(),
                recipe.getSlug(),
                starer
        ).orElse(null);
        assertThat(star, is(notNullValue()));
    }

    @Test
    public void deleteViaUsernameAndSlug() {
        final User owner = this.seedUser();
        final User starer = this.seedUser();
        final Recipe recipe = this.seedRecipe(owner);
        this.recipeStarService.create(recipe.getId(), starer.getId());
        assertDoesNotThrow(() -> this.recipeStarService.delete(
                recipe.getOwner().getUsername(),
                recipe.getSlug(),
                starer
        ));
    }

}
