import {
  boolean,
  doublePrecision,
  index,
  integer,
  jsonb,
  pgTable,
  primaryKey,
  text,
  timestamp,
  uniqueIndex,
  uuid,
} from "drizzle-orm/pg-core";
import type { NutritionValues, RecipeDNA, Season } from "@app/shared-types";
import {
  allergenEnum,
  createdAt,
  cuisineEnum,
  mealTypeEnum,
  recipeDifficultyEnum,
  recipeSimilarityClassEnum,
  recipeSourceTypeEnum,
  recipeStatusEnum,
  recipeVariantTypeEnum,
  recipeVerificationStatusEnum,
  unitEnum,
  updatedAt,
} from "./_shared.js";
import { canonicalIngredients } from "./ingredients.js";
import { users } from "./users.js";

/** Juridiskt source registry (spec §15). */
export const recipeSourceRegistry = pgTable("recipe_source_registry", {
  id: uuid("id").primaryKey().defaultRandom(),
  sourceName: text("source_name").notNull(),
  license: text("license").notNull(),
  rightToStore: boolean("right_to_store").notNull(),
  rightToModify: boolean("right_to_modify").notNull(),
  rightToDisplay: boolean("right_to_display").notNull(),
  attributionRequired: boolean("attribution_required").notNull().default(false),
  attributionText: text("attribution_text"),
  commercialUse: boolean("commercial_use").notNull(),
  validFrom: timestamp("valid_from", { withTimezone: true }).notNull().defaultNow(),
  validTo: timestamp("valid_to", { withTimezone: true }),
  notes: text("notes"),
  createdAt: createdAt(),
});

export const recipes = pgTable(
  "recipes",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    slug: text("slug").notNull(),
    titleSv: text("title_sv").notNull(),
    descriptionSv: text("description_sv").notNull().default(""),
    country: text("country"),
    region: text("region"),
    cuisine: cuisineEnum("cuisine").notNull(),
    mealTypes: mealTypeEnum("meal_types").array().notNull().default([]),
    tags: text("tags").array().notNull().default([]),
    methods: text("methods").array().notNull().default([]),
    equipment: text("equipment").array().notNull().default([]),
    difficulty: recipeDifficultyEnum("difficulty").notNull().default("easy"),
    prepTimeMinutes: integer("prep_time_minutes").notNull().default(0),
    cookTimeMinutes: integer("cook_time_minutes").notNull().default(0),
    totalTimeMinutes: integer("total_time_minutes").notNull().default(0),
    portions: integer("portions").notNull().default(4),
    /** Beräknas ALLTID deterministiskt av nutrition-engine (spec §61.1). */
    nutritionPerPortion: jsonb("nutrition_per_portion").$type<NutritionValues>().notNull(),
    /** Härledda ur ingrediensernas allergener – deterministiskt (spec §61.2). */
    allergens: allergenEnum("allergens").array().notNull().default([]),
    spiceLevel: integer("spice_level").notNull().default(0),
    estimatedCostMinorPerPortion: integer("estimated_cost_minor_per_portion"),
    storageGuidanceSv: text("storage_guidance_sv"),
    mealPrepFriendly: boolean("meal_prep_friendly").notNull().default(false),
    freezerFriendly: boolean("freezer_friendly").notNull().default(false),
    peakSeasons: text("peak_seasons").array().$type<Season[]>().notNull().default([]),
    holidayTags: text("holiday_tags").array().notNull().default([]),
    dna: jsonb("dna").$type<RecipeDNA>().notNull(),
    variantType: recipeVariantTypeEnum("variant_type").notNull().default("standard"),
    variantOfRecipeId: uuid("variant_of_recipe_id"),
    forkedFromRecipeId: uuid("forked_from_recipe_id"),
    status: recipeStatusEnum("status").notNull().default("draft"),
    verificationStatus: recipeVerificationStatusEnum("verification_status")
      .notNull()
      .default("unverified"),
    sourceType: recipeSourceTypeEnum("source_type").notNull(),
    sourceRegistryId: uuid("source_registry_id").references(() => recipeSourceRegistry.id),
    creatorUserId: uuid("creator_user_id").references(() => users.id, { onDelete: "set null" }),
    creatorDisplayName: text("creator_display_name"),
    imageUrls: text("image_urls").array().notNull().default([]),
    version: integer("version").notNull().default(1),
    ratingAverage: doublePrecision("rating_average"),
    ratingCount: integer("rating_count").notNull().default(0),
    cookCount: integer("cook_count").notNull().default(0),
    favoriteCount: integer("favorite_count").notNull().default(0),
    moderationNote: text("moderation_note"),
    createdAt: createdAt(),
    updatedAt: updatedAt(),
  },
  (t) => [
    uniqueIndex("recipes_slug_unique").on(t.slug),
    index("recipes_status_idx").on(t.status),
    index("recipes_cuisine_idx").on(t.cuisine),
    index("recipes_variant_of_idx").on(t.variantOfRecipeId),
    index("recipes_creator_idx").on(t.creatorUserId),
    index("recipes_total_time_idx").on(t.totalTimeMinutes),
  ],
);

export const recipeIngredients = pgTable(
  "recipe_ingredients",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    recipeId: uuid("recipe_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    canonicalIngredientId: text("canonical_ingredient_id")
      .notNull()
      .references(() => canonicalIngredients.id),
    displayNameSv: text("display_name_sv").notNull(),
    quantity: doublePrecision("quantity").notNull(),
    unit: unitEnum("unit").notNull(),
    note: text("note"),
    optional: boolean("optional").notNull().default(false),
    groupName: text("group_name"),
    sortOrder: integer("sort_order").notNull().default(0),
  },
  (t) => [
    index("recipe_ingredients_recipe_idx").on(t.recipeId),
    index("recipe_ingredients_canonical_idx").on(t.canonicalIngredientId),
  ],
);

export const recipeSteps = pgTable(
  "recipe_steps",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    recipeId: uuid("recipe_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    stepNumber: integer("step_number").notNull(),
    instructionSv: text("instruction_sv").notNull(),
    timerSeconds: integer("timer_seconds"),
    temperatureC: integer("temperature_c"),
    tip: text("tip"),
  },
  (t) => [
    index("recipe_steps_recipe_idx").on(t.recipeId),
    uniqueIndex("recipe_steps_recipe_step_unique").on(t.recipeId, t.stepNumber),
  ],
);

export const recipeRatings = pgTable(
  "recipe_ratings",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    recipeId: uuid("recipe_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    stars: integer("stars").notNull(),
    feedbackTags: text("feedback_tags").array().notNull().default([]),
    comment: text("comment"),
    createdAt: createdAt(),
    updatedAt: updatedAt(),
  },
  (t) => [
    uniqueIndex("recipe_ratings_user_recipe_unique").on(t.recipeId, t.userId),
    index("recipe_ratings_recipe_idx").on(t.recipeId),
  ],
);

export const recipeFavorites = pgTable(
  "recipe_favorites",
  {
    recipeId: uuid("recipe_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    createdAt: createdAt(),
  },
  (t) => [
    primaryKey({ columns: [t.recipeId, t.userId] }),
    index("recipe_favorites_user_idx").on(t.userId),
  ],
);

/** Logg över lagningar – grund för betyg, ranking, Food Memory (spec §37–39). */
export const recipeCooks = pgTable(
  "recipe_cooks",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    recipeId: uuid("recipe_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    householdId: uuid("household_id"),
    portionsCooked: integer("portions_cooked").notNull(),
    cookedAt: timestamp("cooked_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    index("recipe_cooks_recipe_idx").on(t.recipeId),
    index("recipe_cooks_user_idx").on(t.userId),
  ],
);

/** Dubblett-/variantklassning mellan recept (spec §36). */
export const recipeSimilarities = pgTable(
  "recipe_similarities",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    recipeAId: uuid("recipe_a_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    recipeBId: uuid("recipe_b_id")
      .notNull()
      .references(() => recipes.id, { onDelete: "cascade" }),
    similarityScore: doublePrecision("similarity_score").notNull(),
    classification: recipeSimilarityClassEnum("classification").notNull(),
    details: jsonb("details"),
    createdAt: createdAt(),
  },
  (t) => [uniqueIndex("recipe_similarities_pair_unique").on(t.recipeAId, t.recipeBId)],
);
