package app.mealsmadeeasy.api;

import app.mealsmadeeasy.api.image.Image;
import app.mealsmadeeasy.api.image.ImageService;
import app.mealsmadeeasy.api.image.spec.ImageCreateSpec;
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.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import java.util.stream.Stream;

@Configuration
@Profile("dev")
public class DevConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(DevConfiguration.class);

    private final UserService userService;
    private final RecipeService recipeService;
    private final ImageService imageService;

    private final ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory());

    public DevConfiguration(UserService userService, RecipeService recipeService, ImageService imageService) {
        this.userService = userService;
        this.recipeService = recipeService;
        this.imageService = imageService;
    }

    private static final class ImageInfo {
        public String src;
        public String title;
        public String alt;
        public String caption;
        public boolean isPublic;
    }

    private static final class RecipeFrontMatter {
        public String title;
        public String slug;
        public boolean isPublic;
        public ImageInfo mainImage;
    }

    @Bean
    public CommandLineRunner addTestData() {
        return args -> {
            final User testUser = this.userService.createUser(
                    "test-user", "test-user@test.com", "test", Set.of()
            );
            logger.info("Created testUser: {}", testUser);

            try (final Stream<Path> recipePaths = Files.walk(Path.of("dev-data/recipes"))) {
                for (final Path recipePath : recipePaths.toList()) {
                    if (Files.isDirectory(recipePath)) {
                        continue;
                    }

                    final String fullText = Files.readString(recipePath);
                    final String[] parts = fullText.split("---");
                    if (parts.length != 3) {
                        throw new IllegalArgumentException("Invalid recipe file: " + recipePath);
                    }
                    final String rawFrontMatter = parts[1];
                    final String rawRecipeText = parts[2];
                    final RecipeFrontMatter frontMatter = this.yamlObjectMapper.readValue(
                            rawFrontMatter, RecipeFrontMatter.class
                    );

                    final ImageCreateSpec imageCreateSpec = ImageCreateSpec.builder()
                            .alt(frontMatter.mainImage.alt)
                            .caption(frontMatter.mainImage.caption)
                            .isPublic(frontMatter.mainImage.isPublic)
                            .build();
                    final Path givenPath = Path.of(frontMatter.mainImage.src);
                    final Path resolvedPath = Path.of("dev-data", "images").resolve(givenPath);
                    final Image mainImage;
                    try (final InputStream inputStream = new FileInputStream(resolvedPath.toFile())) {
                        final long size = Files.size(resolvedPath);
                        mainImage = this.imageService.create(
                                testUser,
                                givenPath.getName(givenPath.getNameCount() - 1).toString(),
                                inputStream,
                                size,
                                imageCreateSpec
                        );
                        logger.info("Created mainImage {} for {}", mainImage, recipePath);
                    }

                    final RecipeCreateSpec recipeCreateSpec = RecipeCreateSpec.builder()
                            .slug(frontMatter.slug)
                            .title(frontMatter.title)
                            .rawText(rawRecipeText)
                            .isPublic(frontMatter.isPublic)
                            .mainImage(mainImage)
                            .build();
                    final Recipe recipe = this.recipeService.create(testUser, recipeCreateSpec, true);
                    logger.info("Created recipe {}", recipe);
                }
            }
        };
    }

}
