import type {RecipeModel} from "../models/RecipeModel"
import type {RecipeDto} from "../api/dtos/RecipeDto"
import type {RecipeIngredientGroupDto} from "../api/dtos/RecipeIngredientGroupDto"
import type {RecipeInstructionStepDto} from "../api/dtos/RecipeInstructionStepDto"

/**
 * Maps a RecipeDto (as returned by the backend) to the Recipe model
 * used in the frontend application.
 */
export function mapRecipeDtoToModel(dto: RecipeDto): RecipeModel {
    return {
        id: dto.id,
        title: dto.title,

        servings: {
            amount: dto.amount ?? 1,
            unit: dto.amountDescription ?? "",
        },
        // join all instruction step texts into a single string for display
        instructionStepList: dto.instructions
            .sort((a, b) => a.sortOrder - b.sortOrder) // ensure correct order
            .map(step => ({
                    text: step.text,
                    id: step.id,
                    /* When mapping a stepDTO, it should already contain a UUID. If
                     * If, however, for some reason, it does not, add a UUID as sorting
                     * steps in teh GUI requires a unique identifier for each item.
                     */
                    internalId: step.id !== undefined ? step.id : crypto.randomUUID()
                })
            ),

        ingredientGroupList: dto.ingredientGroups
            .sort((a, b) => a.sortOrder - b.sortOrder) // ensure groups are ordered
            .map(group => ({
                id: group.id,
                title: group.title,
                ingredientList: group.ingredients
                    .sort((a, b) => a.sortOrder - b.sortOrder) // ensure ingredients are ordered
                    .map(ing => ({
                        id: ing.id,
                        name: ing.name ?? "", // @todo ensure that name and amount are indeed present
                        amount: ing.amount,
                        unit: ing.unit,
                        //subtext: ing.subtext ?? undefined,
                    })),
            })),
        imageUrl: undefined, // not part of DTO yet, placeholder
    }
}

/**
 * Maps a Recipe model (as used in the frontend) back to a RecipeDto
 * for sending updates or creations to the backend.
 */
export function mapRecipeModelToDto(model: RecipeModel): RecipeDto {
    // Map instructions
    const instructionDtos: RecipeInstructionStepDto[] = model.instructionStepList.map(
        (step, index) => ({
            id: step.id,
            text: step.text,
            sortOrder: index + 1,
        })
    )

    // Map ingredients
    const ingredientGroupDtos: RecipeIngredientGroupDto[] =
        model.ingredientGroupList.map((group, groupIndex) => ({
            id: group.id,
            title: group.title,
            sortOrder: groupIndex + 1, // sortOrder from list index
            ingredients: group.ingredientList.map((ing, ingIndex) => ({
                id: ing.id,
                name: ing.name,
                amount: ing.amount,
                unit: ing.unit,
                sortOrder: ingIndex + 1, // sortOrder from index
                //subtext: ing.subtext ?? null,
            })),
        }))

    return {
        id: model.id,
        title: model.title,
        amount: model.servings.amount,
        amountDescription: model.servings.unit,
        instructions: instructionDtos,
        ingredientGroups: ingredientGroupDtos,
    }
}
