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

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

enum Role {
  SERVER_ADMIN
  TENANT_ADMIN
  OPERATOR
  VIEWER
}

enum IconType {
  STANDARD
  RETTUNG
  GEFAHRSTOFF
  FEUER
  WASSER
  FAHRZEUG
}

enum ItemKind {
  SYMBOL
  LINE
  POLYGON
  RECTANGLE
  CIRCLE
  ARROW
  TEXT
}

enum SubscriptionPlan {
  FREE
  PRO
}

enum DictionaryScope {
  GLOBAL
  TENANT
}

enum SubscriptionStatus {
  ACTIVE
  TRIAL
  SUSPENDED
  EXPIRED
  CANCELLED
}

model Tenant {
  id          String   @id @default(uuid())
  name        String
  slug        String   @unique
  description String?
  isActive    Boolean  @default(true)
  contactEmail String?
  contactPhone String?
  address      String?

  logoUrl      String?
  logoFileKey  String?

  // Subscription
  plan            SubscriptionPlan   @default(FREE)
  subscriptionStatus SubscriptionStatus @default(ACTIVE)
  trialEndsAt     DateTime?
  subscriptionEndsAt DateTime?
  maxUsers        Int      @default(5)
  maxProjects     Int      @default(10)
  notes           String?
  hiddenIconIds       String[] @default([])
  journalSuggestions  String[] @default([])
  // Modul-Baukasten: Cockpit-Konfiguration (siehe src/lib/modules.ts). NULL = Standard.
  modulesConfig       Json?

  // Privacy consent
  privacyAccepted      Boolean  @default(false)
  privacyAcceptedAt    DateTime?
  adminAccessAccepted  Boolean  @default(false)

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

  memberships       TenantMembership[]
  projects          Project[]
  hoseTypes         HoseType[]
  checkTemplates    JournalCheckTemplate[]
  iconCategories    IconCategory[]
  iconAssets        IconAsset[]
  tenantSymbols     TenantSymbol[]
  tenantCategories  TenantCategory[]
  upgradeRequests   UpgradeRequest[]
  dictionaryEntries DictionaryEntry[]
  rapports          Rapport[]

  @@map("tenants")
}

// ─── System Settings (Key-Value, encrypted for secrets) ──────

model SystemSetting {
  id        String   @id @default(uuid())
  key       String   @unique
  value     String
  isSecret  Boolean  @default(false)
  category  String   @default("general")
  updatedAt DateTime @updatedAt

  @@map("system_settings")
}

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  password  String
  name      String
  role      Role     @default(OPERATOR)
  emailVerified          Boolean  @default(true)
  // Super-Admin kann einzelne Benutzer sperren; gesperrte können sich nicht mehr anmelden.
  isActive               Boolean  @default(true)
  emailVerificationToken String?  @unique
  resetToken      String?  @unique
  resetTokenExpiry DateTime?
  lastLoginAt     DateTime?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  memberships      TenantMembership[]
  projects          Project[]
  iconAssets        IconAsset[]
  upgradeRequests   UpgradeRequest[]
  rapports          Rapport[]

  @@map("users")
}

model TenantMembership {
  id        String   @id @default(uuid())
  role      Role     @default(OPERATOR)
  createdAt DateTime @default(now())

  userId   String
  user     User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  tenantId String
  tenant   Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  @@unique([userId, tenantId])
  @@map("tenant_memberships")
}

model Project {
  id          String   @id @default(uuid())
  einsatzNr   String?
  // "EINSATZ" = echter Einsatz (mit Journal), "UEBUNG" = Übung (Cockpit statt Journal).
  // Als String (nicht Enum) gehalten, damit die idempotente Raw-SQL-Migration einfach bleibt.
  mode        String   @default("EINSATZ")
  // Nur für Übungen: Gesamt-Auswertung / Lessons Learned (Freitext).
  exerciseEvaluation String?
  title       String
  location    String?
  description    String?
  einsatzleiter  String?
  journalfuehrer String?
  mapCenter      Json     @default("{\"lng\": 8.5417, \"lat\": 47.3769}")
  mapZoom        Float    @default(15)
  // Windrichtung in Grad (meteorologisch „Wind aus"), fürs Lagebild. NULL = nicht gesetzt.
  windDirection  Int?
  isLocked    Boolean  @default(false)
  // Optimistische Nebenläufigkeit: wird bei jedem Features-Speichern hochgezählt.
  // Verhindert, dass ein veralteter (z.B. offline zwischengespeicherter) Stand
  // neuere Änderungen stillschweigend überschreibt.
  featuresVersion Int   @default(0)

  // Live editing lock (session-based for same-account multi-device)
  editingById       String?
  editingUserName   String?
  editingSessionId  String?
  editingStartedAt  DateTime?
  editingHeartbeat  DateTime?

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

  ownerId  String?
  owner    User?   @relation(fields: [ownerId], references: [id], onDelete: SetNull)
  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)

  features          Feature[]
  items             Item[]
  journalEntries    JournalEntry[]
  journalCheckItems JournalCheckItem[]
  journalPendenzen  JournalPendenz[]
  exerciseGoals     ExerciseGoal[]
  rapports          Rapport[]
  moduleItems       ModuleItem[]

  @@map("projects")
}

// ─── Übungs-Cockpit: Übungsziele mit Zielerreichung ──────────

model ExerciseGoal {
  id        String   @id @default(uuid())
  text      String
  // Zielerreichung: OPEN | REACHED | PARTIAL | MISSED
  status    String   @default("OPEN")
  note      String?
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  projectId String
  project   Project  @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@index([projectId])
  @@map("exercise_goals")
}

model Feature {
  id         String   @id @default(uuid())
  type       String
  geometry   Json
  properties Json     @default("{}")
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@map("features")
}

model IconCategory {
  id          String   @id @default(uuid())
  name        String
  description String?
  sortOrder   Int      @default(0)
  isGlobal    Boolean  @default(false)
  createdAt   DateTime @default(now())

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)

  icons IconAsset[]

  @@map("icon_categories")
}

model IconAsset {
  id        String    @id @default(uuid())
  name      String
  fileKey   String
  mimeType  String
  width     Int?
  height    Int?
  isSystem  Boolean   @default(false)
  isActive  Boolean   @default(true)
  iconType  IconType  @default(STANDARD)
  tags      String[]  @default([])
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt

  categoryId String?
  category   IconCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)

  ownerId String?
  owner   User?   @relation(fields: [ownerId], references: [id], onDelete: SetNull)

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)

  tenantSymbols TenantSymbol[]

  @@map("icon_assets")
}

model HoseType {
  id              String   @id @default(uuid())
  name            String   @unique
  diameterMm      Int
  lengthPerPieceM Int      @default(10)
  flowRateLpm     Float
  frictionCoeff   Float
  description     String?
  isDefault       Boolean  @default(false)
  isActive        Boolean  @default(true)
  sortOrder       Int      @default(0)
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)

  @@map("hose_types")
}

// ─── Journal ───────────────────────────────────────────────

model JournalEntry {
  id        String   @id @default(uuid())
  time      DateTime @default(now())
  what      String
  who       String?
  done      Boolean  @default(false)
  doneAt    DateTime?
  sortOrder Int      @default(0)
  isCorrected Boolean @default(false)
  correctionOfId String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@map("journal_entries")
}

model JournalCheckItem {
  id        String   @id @default(uuid())
  label     String
  confirmed Boolean  @default(false)
  confirmedAt DateTime?
  ok        Boolean  @default(false)
  okAt      DateTime?
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@map("journal_check_items")
}

model JournalPendenz {
  id        String   @id @default(uuid())
  what      String
  who       String?
  whenHow   String?
  done      Boolean  @default(false)
  doneAt    DateTime?
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@map("journal_pendenzen")
}

// Generischer Datenspeicher für Tabellen-Module (Modul-Baukasten).
// data enthält die Zellwerte gemäss Spaltendefinition des Moduls,
// z.B. { "trupp": "Trupp 1", "druck": "280", "out": true, "outAt": "..." }
model ModuleItem {
  id        String   @id @default(uuid())
  moduleId  String
  data      Json     @default("{}")
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@index([projectId, moduleId])
  @@map("module_items")
}

model JournalCheckTemplate {
  id        String   @id @default(uuid())
  label     String
  sortOrder Int      @default(0)
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)

  @@map("journal_check_templates")
}

model Item {
  id         String    @id @default(uuid())
  kind       ItemKind
  geometry   Json
  style      Json      @default("{}")
  properties Json      @default("{}")
  isVisible  Boolean   @default(true)
  sortOrder  Int       @default(0)
  createdAt  DateTime  @default(now())
  updatedAt  DateTime  @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  iconId String?

  @@map("items")
}

// ─── Upgrade Requests ─────────────────────────────────────

enum UpgradeRequestStatus {
  PENDING
  APPROVED
  REJECTED
}

model UpgradeRequest {
  id              String               @id @default(uuid())
  requestedPlan   SubscriptionPlan
  currentPlan     SubscriptionPlan
  message         String?
  status          UpgradeRequestStatus @default(PENDING)
  adminNote       String?
  processedAt     DateTime?
  processedById   String?
  createdAt       DateTime             @default(now())
  updatedAt       DateTime             @updatedAt

  tenantId String
  tenant   Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  requestedById String
  requestedBy   User @relation(fields: [requestedById], references: [id], onDelete: Cascade)

  @@map("upgrade_requests")
}

// ─── Tenant Symbol Collection ─────────────────────────────

model TenantSymbol {
  id         String   @id @default(uuid())
  customName String?
  sortOrder  Int      @default(0)
  createdAt  DateTime @default(now())

  tenantId String
  tenant   Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  iconId String?
  icon   IconAsset? @relation(fields: [iconId], references: [id], onDelete: SetNull)

  // New fields for Phase 1 Symbol Architecture
  categoryId String?
  category   TenantCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)

  name       String?  // Display name (migrated from customName || icon.name)
  svgPath    String?  // e.g. "signaturen/TLF.svg" or tenant-specific MinIO key
  isUploaded Boolean  @default(false)
  migratedFromIconId String?

  @@index([tenantId])
  @@index([categoryId])
  @@map("tenant_symbols")
}

// ─── Symbol Templates (global read-only packages) ─────────

model SymbolTemplate {
  id           String   @id @default(uuid())
  packageId    String   // e.g. "feuerwehr-ch"
  packageName  String   // e.g. "Feuerwehr Schweiz"
  categoryName String   // e.g. "Fahrzeuge"
  name         String
  svgPath      String   // relative path in public/ or MinIO key
  tags         String[] @default([])
  sortOrder    Int      @default(0)

  @@index([packageId])
  @@map("symbol_templates")
}

// ─── Tenant Categories (per-tenant, user-managed) ─────────

model TenantCategory {
  id        String   @id @default(uuid())
  tenantId  String
  tenant    Tenant   @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  name      String
  sortOrder Int      @default(0)
  icon      String?  // Optional emoji or Lucide icon name for UI

  symbols   TenantSymbol[]

  @@unique([tenantId, name])
  @@index([tenantId])
  @@map("tenant_categories")
}

// ─── Dictionary (Global + Tenant word library) ────────────

model DictionaryEntry {
  id        String          @id @default(uuid())
  word      String
  scope     DictionaryScope @default(GLOBAL)
  createdAt DateTime        @default(now())

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  @@unique([word, tenantId])
  @@map("dictionary_entries")
}

// ─── Rapport (PDF reports with public token access) ───────

model Rapport {
  id           String   @id @default(uuid())
  reportNumber String
  token        String   @unique @default(uuid())
  data         Json
  generatedAt  DateTime @default(now())
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  projectId String
  project   Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  tenantId String?
  tenant   Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  createdById String?
  createdBy   User?   @relation(fields: [createdById], references: [id], onDelete: SetNull)

  @@map("rapports")
}
