import { generateObject } from "ai";
import { z } from "zod";
import { resolveModel, type AiConfig } from "../factory";
import { dietaryTagsSchema, ingredientSchema, stepSchema } from "./recipe-schema";

export const MEAL_COURSES = ["starter", "main", "side", "dessert", "drink"] as const;
export type MealCourse = (typeof MEAL_COURSES)[number];

const MealOutputSchema = z.object({
  recipes: z.array(z.object({
    course: z.enum(MEAL_COURSES),
    recipeType: z.enum(["dish", "drink"]).describe("\"drink\" only for a beverage/cocktail with no cooking step."),
    title: z.string().max(150),
    description: z.string().max(300),
    baseServings: z.number().int().min(1).max(100),
    prepMins: z.number().int().min(0).max(360).optional(),
    cookMins: z.number().int().min(0).max(360).optional(),
    difficulty: z.enum(["easy", "medium", "hard"]).optional(),
    dietaryTags: dietaryTagsSchema,
    ingredients: z.array(ingredientSchema(z.number())).max(30),
    steps: z.array(stepSchema).max(20),
  })).min(1).max(6),
});

export type GeneratedMeal = z.infer<typeof MealOutputSchema>;

const LANG: Record<string, string> = { en: "English", fr: "French" };

/** Generates a themed, coherent set of recipes in one call — one per
 *  requested course — so they read as a matching meal (shared cuisine,
 *  complementary flavors) rather than N unrelated recipes. */
export async function generateMeal(
  options: {
    theme: string;
    courses: MealCourse[];
    servings?: number;
    dietaryPrefs?: string;
    difficulty?: "easy" | "medium" | "hard";
  },
  config?: AiConfig & { userContext?: string },
  locale?: string
): Promise<GeneratedMeal> {
  const model = resolveModel(config);
  const lang = LANG[locale ?? "en"] ?? "English";
  const servings = options.servings ?? 4;

  const dietaryClause = options.dietaryPrefs?.trim() ? `Dietary requirements: ${options.dietaryPrefs.trim()}.` : "";
  const difficultyClause = options.difficulty
    ? `All recipes must be ${options.difficulty} difficulty: ${{ easy: "simple techniques, few steps, everyday ingredients", medium: "moderate skill, standard techniques", hard: "advanced techniques, multiple components" }[options.difficulty]}.`
    : "";

  const systemPrompt =
    `You are a professional chef planning a complete, coherent meal — not a list of unrelated recipes. ` +
    `Generate exactly one recipe per requested course, all sharing a consistent cuisine/style that fits the theme, ` +
    `with flavors and ingredients that complement each other across courses (e.g. a light starter before a rich main, ` +
    `a dessert or drink that fits the same culinary tradition). For ingredients: quantity must be a number only ` +
    `(e.g. 0.25, 1.5, 2), unit is a separate string (e.g. 'cup', 'tbsp', 'g', 'ml') — never combine them. ` +
    `Set recipeType to "drink" only for a beverage/cocktail with no cooking step; for a drink, omit cookMins and ` +
    `default baseServings to 1 unless the theme implies otherwise. Respond in ${lang}.` +
    (config?.userContext ? `\n\nUser preferences and context:\n${config.userContext}` : "");

  const { object } = await generateObject({
    model,
    schema: MealOutputSchema,
    system: systemPrompt,
    prompt: [
      `Theme: ${options.theme.trim()}.`,
      `Generate these courses, in this order: ${options.courses.join(", ")}.`,
      `Plan for ${servings} servings per course (except drinks, which default to 1 unless stated otherwise).`,
      dietaryClause,
      difficultyClause,
    ].filter(Boolean).join(" "),
  });

  // Belt-and-suspenders in case the model ignores the drink-specific
  // instructions above — same rationale as generateRecipe().
  return {
    recipes: object.recipes.map((r) => (r.recipeType === "drink" ? { ...r, cookMins: undefined } : r)),
  };
}
