import { z } from "zod";
import {
  ALLERGENS,
  COOKING_METHODS,
  CUISINES,
  EQUIPMENT,
  FEEDBACK_TAGS,
  MEAL_TYPES,
  RECIPE_DIFFICULTIES,
  RECIPE_TAGS,
} from "@app/shared-types";
import { quantitySchema, unitSchema, uuidSchema } from "./common.js";

export const recipeQuerySchema = z.object({
  search: z.string().max(120).optional(),
  cuisine: z.enum(CUISINES).optional(),
  mealType: z.enum(MEAL_TYPES).optional(),
  tags: z
    .union([z.enum(RECIPE_TAGS), z.array(z.enum(RECIPE_TAGS))])
    .transform((v) => (Array.isArray(v) ? v : [v]))
    .optional(),
  method: z.enum(COOKING_METHODS).optional(),
  maxTotalMinutes: z.coerce.number().int().min(1).max(600).optional(),
  maxKcalPerPortion: z.coerce.number().int().min(50).max(5000).optional(),
  minProteinPerPortion: z.coerce.number().int().min(0).max(300).optional(),
  maxCostMinorPerPortion: z.coerce.number().int().min(0).max(100_000).optional(),
  difficulty: z.enum(RECIPE_DIFFICULTIES).optional(),
  excludeAllergens: z
    .union([z.enum(ALLERGENS), z.array(z.enum(ALLERGENS))])
    .transform((v) => (Array.isArray(v) ? v : [v]))
    .optional(),
  creatorUserId: uuidSchema.optional(),
  sort: z.enum(["relevance", "rating", "cooked", "newest", "time", "cost"]).default("relevance"),
  limit: z.coerce.number().int().min(1).max(50).default(20),
  offset: z.coerce.number().int().min(0).default(0),
});
export type RecipeQuery = z.infer<typeof recipeQuerySchema>;

const recipeIngredientInputSchema = z.object({
  canonicalIngredientId: z.string().min(1).max(80),
  displayNameSv: z.string().min(1).max(120),
  quantity: quantitySchema,
  unit: unitSchema,
  note: z.string().max(120).optional(),
  optional: z.boolean().default(false),
  groupName: z.string().max(60).optional(),
});

const recipeStepInputSchema = z.object({
  instructionSv: z.string().min(3).max(1000),
  timerSeconds: z.number().int().min(5).max(86_400).optional(),
  temperatureC: z.number().int().min(30).max(350).optional(),
  tip: z.string().max(300).optional(),
});

/**
 * Användarrecept (spec §35): antingen strukturerat direkt, eller fritext som
 * AI strukturerar (via AAMOS) och användaren sedan granskar.
 */
export const createUserRecipeInputSchema = z.discriminatedUnion("mode", [
  z.object({
    mode: z.literal("structured"),
    titleSv: z.string().min(3).max(150),
    descriptionSv: z.string().max(2000).default(""),
    cuisine: z.enum(CUISINES).default("international"),
    mealTypes: z.array(z.enum(MEAL_TYPES)).min(1),
    tags: z.array(z.enum(RECIPE_TAGS)).default([]),
    methods: z.array(z.enum(COOKING_METHODS)).default([]),
    equipment: z.array(z.enum(EQUIPMENT)).default([]),
    difficulty: z.enum(RECIPE_DIFFICULTIES).default("easy"),
    prepTimeMinutes: z.number().int().min(0).max(600),
    cookTimeMinutes: z.number().int().min(0).max(1440),
    portions: z.number().int().min(1).max(24),
    spiceLevel: z.number().int().min(0).max(5).default(0),
    ingredients: z.array(recipeIngredientInputSchema).min(1).max(60),
    steps: z.array(recipeStepInputSchema).min(1).max(40),
  }),
  z.object({
    mode: z.literal("free_text"),
    text: z.string().min(20).max(8000),
  }),
]);
export type CreateUserRecipeInput = z.infer<typeof createUserRecipeInputSchema>;

export const rateRecipeInputSchema = z.object({
  stars: z.number().int().min(1).max(5),
  feedbackTags: z.array(z.enum(FEEDBACK_TAGS)).max(8).default([]),
  comment: z.string().max(1000).optional(),
});
export type RateRecipeInput = z.infer<typeof rateRecipeInputSchema>;

/** "Jag har lagat detta" – kärnflödet som drar lager och loggar måltid (spec §23). */
export const cookRecipeInputSchema = z.object({
  portionsCooked: z.number().int().min(1).max(24),
  /** Vilka i hushållet som åt, med portionsandel per person. */
  eaters: z
    .array(
      z.object({
        userId: uuidSchema,
        portionFraction: z.number().min(0.1).max(3).default(1),
      }),
    )
    .default([]),
  /** Portioner som blev matlådor (spec §24). */
  mealBoxPortions: z.number().int().min(0).max(24).default(0),
  mealBoxStorageLocationId: uuidSchema.optional(),
  mealBoxFrozen: z.boolean().default(false),
  /** Dra ingredienser från lagret? Förifyllt förslag visas i appen. */
  deductInventory: z.boolean().default(true),
  /** Justeringar av vad som faktiskt användes. */
  inventoryOverrides: z
    .array(
      z.object({
        canonicalIngredientId: z.string().max(80),
        quantityUsed: z.number().min(0),
        unit: unitSchema,
      }),
    )
    .default([]),
  date: z
    .string()
    .regex(/^\d{4}-\d{2}-\d{2}$/)
    .optional(),
  mealType: z.enum(MEAL_TYPES).default("dinner"),
});
export type CookRecipeInput = z.infer<typeof cookRecipeInputSchema>;

export const substitutionQuerySchema = z.object({
  fromIngredientId: z.string().min(1).max(80),
  context: z.string().max(60).optional(),
});
export type SubstitutionQuery = z.infer<typeof substitutionQuerySchema>;
