generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id           Int          @id @default(autoincrement())
  username     String       @unique
  email        String       @unique
  firstName    String?
  lastName     String?
  passwordHash String
  role         String       @default("user")
  isPremium    Boolean      @default(false)
  canShareRecipes Boolean   @default(true)
  aiEngineEnabled Boolean   @default(false)
  createdAt    DateTime     @default(now())
  updatedAt    DateTime     @updatedAt

  userProducts UserProduct[]
  ownedRecipes Recipe[]      @relation("RecipeOwner")
  sharedRecipes RecipeShare[]
  ownedProducts Product[]
  inventoryItems InventoryItem[]
  pantryItems PantryItem[]
  mealPlanEntries MealPlanEntry[]
  receiptAliases  ReceiptAlias[]
  unitMappings     UnitMapping[]
  flyerSessions    FlyerSession[]
  flyerSelections  FlyerSelection[]
  shoppingListItems ShoppingListItem[]
  aiTraces          AiTrace[]
}

model Product {
  id             Int             @id @default(autoincrement())
  name           String
  normalizedName String          @unique
  canonicalName  String?
  isActive       Boolean         @default(true)
  status         String           @default("active")
  deletedAt      DateTime?
  createdAt      DateTime        @default(now())
  updatedAt      DateTime        @updatedAt

  inventoryItems    InventoryItem[]
  recipeIngredients RecipeIngredient[]
  pantryItems       PantryItem[]
  receiptAliases    ReceiptAlias[]
  tags              ProductTag[]
  nutrition         Nutrition?
  ownerId           Int
  owner             User            @relation(fields: [ownerId], references: [id], onDelete: Cascade)
  userProducts      UserProduct[]
  categoryId        Int?
  categoryRef       Category?       @relation(fields: [categoryId], references: [id], onDelete: SetNull)
  isPrivate         Boolean         @default(false)
  unitMappings      UnitMapping[]
  shoppingListItems ShoppingListItem[]
}

model Category {
  id       Int        @id @default(autoincrement())
  name     String
  parentId Int?
  parent   Category?  @relation("CategoryTree", fields: [parentId], references: [id], onDelete: SetNull)
  children Category[] @relation("CategoryTree")
  products Product[]
  flyerItems FlyerItem[]
  shoppingListItems ShoppingListItem[]

  @@unique([name, parentId])
  @@index([parentId])
}

model UserProduct {
  id             Int      @id @default(autoincrement())
  userId         Int
  productId      Int
  note           String?  @db.Text
  preferredBrand String?
  preferredStore String?
  isPrivate      Boolean  @default(false)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  user    User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  product Product @relation(fields: [productId], references: [id], onDelete: Cascade)

  @@unique([userId, productId])
  @@index([userId])
  @@index([productId])
}

model InventoryItem {
  id             Int      @id @default(autoincrement())
  userId         Int
  productId      Int
  quantity       Decimal  @db.Decimal(10, 2)
  unit           String
  brand		 String?
  origin         String?
  receiptName    String?
  location       String?
  purchaseDate   DateTime?
  opened         Boolean?
  suitableFor    String?
  bestBeforeDate DateTime?
  comment        String?

  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  user    User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
  consumptions   InventoryConsumption[]

  @@index([userId])
  @@index([productId])
}

model InventoryConsumption {
  id              Int           @id @default(autoincrement())
  inventoryItem   InventoryItem @relation(fields: [inventoryItemId], references: [id])
  inventoryItemId Int
  amountUsed      Decimal       @db.Decimal(10, 2)
  comment         String?
  createdAt       DateTime      @default(now())
}

model Recipe {
  id           Int                @id @default(autoincrement())
  name         String
  description  String?            @db.Text
  instructions String?            @db.Text
  imageUrl     String?
  servings     Int?
  isPublic     Boolean            @default(false)
  ownerId      Int?
  createdAt    DateTime           @default(now())
  updatedAt    DateTime           @updatedAt

  owner           User?            @relation("RecipeOwner", fields: [ownerId], references: [id], onDelete: SetNull)
  ingredients     RecipeIngredient[]
  mealPlanEntries MealPlanEntry[]
  shares          RecipeShare[]
}

model RecipeShare {
  recipeId Int
  userId   Int
  recipe   Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade)
  user     User   @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@id([recipeId, userId])
  @@index([userId])
}

model RecipeIngredient {
  id        Int      @id @default(autoincrement())
  recipe    Recipe   @relation(fields: [recipeId], references: [id])
  recipeId  Int
  product   Product? @relation(fields: [productId], references: [id])
  productId Int?
  rawName   String   @default("")
  rawLine   String?  @db.Text
  quantity  Decimal? @db.Decimal(10, 2)
  unit      String?
  note      String?
  alternativeProductIds Json?   // [id, id, ...] — alternativa produkter (t.ex. "ris eller couscous")
  matchConfidence Float?
  matchSource     String?
  analysisStatus  String?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model PantryItem {
  id        Int      @id @default(autoincrement())
  userId    Int
  productId Int
  location  String?
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  product   Product  @relation(fields: [productId], references: [id], onDelete: Cascade)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@unique([userId, productId])
  @@index([userId])
}

model ReceiptAlias {
  id           Int      @id @default(autoincrement())
  receiptName  String   // normaliserat kvittonamn (lowercase, trim)
  ownerId      Int?
  owner        User?    @relation(fields: [ownerId], references: [id], onDelete: Cascade)
  isGlobal     Boolean  @default(false)
  productId    Int
  product      Product  @relation(fields: [productId], references: [id], onDelete: Cascade)
  createdAt    DateTime @default(now())

  @@unique([receiptName, ownerId, isGlobal])
  @@index([ownerId])
  @@index([isGlobal])
  @@index([receiptName])
}

model MealPlanEntry {
  id        Int      @id @default(autoincrement())
  userId    Int
  date      DateTime @db.Date
  recipe    Recipe   @relation(fields: [recipeId], references: [id], onDelete: Cascade)
  recipeId  Int
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  servings  Int?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // Bara ett recept per dag och anvandare.
  @@unique([userId, date])
  @@index([userId])
  @@index([date])
}

model Tag {
  id       Int          @id @default(autoincrement())
  name     String       @unique
  products ProductTag[]
}

model ProductTag {
  productId Int
  tagId     Int
  product   Product @relation(fields: [productId], references: [id], onDelete: Cascade)
  tag       Tag     @relation(fields: [tagId], references: [id], onDelete: Cascade)

  @@id([productId, tagId])
  @@index([tagId])
}

model Nutrition {
  id            Int     @id @default(autoincrement())
  productId     Int     @unique
  calories      Float?
  protein       Float?
  fat           Float?
  carbohydrates Float?
  salt          Float?
  sugar         Float?
  fiber         Float?
  product       Product @relation(fields: [productId], references: [id], onDelete: Cascade)
}

model UnitMapping {
  id           Int      @id @default(autoincrement())
  productId    Int
  originalUnit String
  preferredUnit String
  userId       Int

  product      Product @relation(fields: [productId], references: [id], onDelete: Cascade)
  user         User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([productId, originalUnit, userId])
  @@index([productId])
  @@index([userId])
}

model HelpText {
  id        Int      @id @default(autoincrement())
  key       String
  scope     String   @default("default")
  title     String
  content   String   @db.Text
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@unique([key, scope])
  @@index([key, isActive])
}

model FlyerSession {
  id         Int              @id @default(autoincrement())
  userId     Int
  retailer   String
  weekKey    String
  status     String           @default("draft")
  createdAt  DateTime         @default(now())
  updatedAt  DateTime         @updatedAt
  expiresAt  DateTime?
  sourceFileName String?
  sourceMimeType String?
  sourceFileSize Int?
  sourceStorageKey String?
  sourceData  Bytes?

  user       User             @relation(fields: [userId], references: [id], onDelete: Cascade)
  items      FlyerItem[]
  selections FlyerSelection[]

  @@index([userId])
  @@index([weekKey])
  @@index([status])
}

model FlyerItem {
  id                 Int              @id @default(autoincrement())
  sessionId          Int
  rawName            String
  normalizedName     String
  brand              String?
  categoryHint       String?
  categoryId         Int?
  price              Decimal?         @db.Decimal(10, 2)
  priceUnit          String?
  comparisonPrice    Decimal?         @db.Decimal(10, 2)
  comparisonUnit     String?
  weight             String?
  bundleWeight       String?
  isBundle           Boolean          @default(false)
  bundleItems        Json?
  offerText          String?
  parseConfidence    Float
  parseReasons       Json?
  matchedProductId   Int?
  matchedProductName String?
  matchedVia         String?
  matchConfidence    Float?
  matchReasons       Json?
  createdAt          DateTime         @default(now())
  updatedAt          DateTime         @updatedAt

  session            FlyerSession     @relation(fields: [sessionId], references: [id], onDelete: Cascade)
  categoryRef        Category?        @relation(fields: [categoryId], references: [id], onDelete: SetNull)
  selections         FlyerSelection[]

  @@index([sessionId])
  @@index([normalizedName])
  @@index([categoryId])
}

model FlyerSelection {
  id              Int          @id @default(autoincrement())
  sessionId       Int
  itemId          Int
  userId          Int
  plannedQuantity Decimal?     @db.Decimal(10, 2)
  plannedUnit     String?
  priority        String       @default("normal")
  note            String?
  status          String       @default("planned")
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt

  session         FlyerSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
  item            FlyerItem    @relation(fields: [itemId], references: [id], onDelete: Cascade)
  user            User         @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([sessionId, itemId])
  @@index([sessionId])
  @@index([userId, status])
}

model ShoppingListItem {
  id         Int      @id @default(autoincrement())
  userId     Int
  name       String
  productId  Int?
  categoryId Int?
  quantity   Decimal? @db.Decimal(10, 2)
  unit       String?
  source     String   @default("manual")
  status     String   @default("open")
  checkedAt  DateTime?
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  user       User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  product    Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
  categoryRef Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)

  @@index([userId, status])
  @@index([productId, unit, status])
  @@index([categoryId])
}

model AiTrace {
  id               Int      @id @default(autoincrement())
  source           String
  userId           Int?
  sessionId        Int?
  model            String?
  prompt           String?  @db.LongText
  rawOutput        String?  @db.LongText
  normalizedOutput Json?
  status           String
  error            String?  @db.Text
  durationMs       Int?
  createdAt        DateTime @default(now())
  updatedAt        DateTime @updatedAt

  user             User?    @relation(fields: [userId], references: [id], onDelete: SetNull)

  @@index([source, createdAt])
  @@index([userId, createdAt])
  @@index([status, createdAt])
}
