package de.effigenix.infrastructure.production.persistence.mapper;

import de.effigenix.domain.production.*;
import de.effigenix.infrastructure.production.persistence.entity.IngredientEntity;
import de.effigenix.infrastructure.production.persistence.entity.ProductionStepEntity;
import de.effigenix.infrastructure.production.persistence.entity.RecipeEntity;
import de.effigenix.shared.common.Quantity;
import de.effigenix.shared.common.UnitOfMeasure;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

@Component
public class RecipeMapper {

    public RecipeEntity toEntity(Recipe recipe) {
        var entity = new RecipeEntity(
                recipe.id().value(),
                recipe.name().value(),
                recipe.version(),
                recipe.type().name(),
                recipe.description(),
                recipe.yieldPercentage().value(),
                recipe.shelfLifeDays(),
                recipe.outputQuantity().amount(),
                recipe.outputQuantity().uom().name(),
                recipe.articleId(),
                recipe.status().name(),
                recipe.createdAt(),
                recipe.updatedAt()
        );

        List<IngredientEntity> ingredientEntities = recipe.ingredients().stream()
                .map(i -> toIngredientEntity(i, entity))
                .collect(Collectors.toList());
        entity.setIngredients(ingredientEntities);

        List<ProductionStepEntity> stepEntities = recipe.productionSteps().stream()
                .map(s -> toProductionStepEntity(s, entity))
                .collect(Collectors.toList());
        entity.setProductionSteps(stepEntities);

        return entity;
    }

    public Recipe toDomain(RecipeEntity entity) {
        List<Ingredient> ingredients = entity.getIngredients().stream()
                .map(this::toDomainIngredient)
                .collect(Collectors.toList());

        List<ProductionStep> productionSteps = entity.getProductionSteps().stream()
                .map(this::toDomainProductionStep)
                .collect(Collectors.toList());

        return Recipe.reconstitute(
                RecipeId.of(entity.getId()),
                new RecipeName(entity.getName()),
                entity.getVersion(),
                RecipeType.valueOf(entity.getType()),
                entity.getDescription(),
                new YieldPercentage(entity.getYieldPercentage()),
                entity.getShelfLifeDays(),
                Quantity.reconstitute(
                        entity.getOutputQuantity(),
                        UnitOfMeasure.valueOf(entity.getOutputUom())
                ),
                entity.getArticleId(),
                RecipeStatus.valueOf(entity.getStatus()),
                ingredients,
                productionSteps,
                entity.getCreatedAt(),
                entity.getUpdatedAt()
        );
    }

    private IngredientEntity toIngredientEntity(Ingredient ingredient, RecipeEntity recipe) {
        return new IngredientEntity(
                ingredient.id().value(),
                recipe,
                ingredient.position(),
                ingredient.articleId(),
                ingredient.quantity().amount(),
                ingredient.quantity().uom().name(),
                ingredient.subRecipeId(),
                ingredient.substitutable()
        );
    }

    private ProductionStepEntity toProductionStepEntity(ProductionStep step, RecipeEntity recipe) {
        return new ProductionStepEntity(
                step.id().value(),
                recipe,
                step.stepNumber(),
                step.description(),
                step.durationMinutes(),
                step.temperatureCelsius()
        );
    }

    private ProductionStep toDomainProductionStep(ProductionStepEntity entity) {
        return ProductionStep.reconstitute(
                ProductionStepId.of(entity.getId()),
                entity.getStepNumber(),
                entity.getDescription(),
                entity.getDurationMinutes(),
                entity.getTemperatureCelsius()
        );
    }

    private Ingredient toDomainIngredient(IngredientEntity entity) {
        return Ingredient.reconstitute(
                IngredientId.of(entity.getId()),
                entity.getPosition(),
                entity.getArticleId(),
                Quantity.reconstitute(
                        entity.getQuantity(),
                        UnitOfMeasure.valueOf(entity.getUom())
                ),
                entity.getSubRecipeId(),
                entity.isSubstitutable()
        );
    }
}
