// =====================================================================
// Kita-Planer · Prisma Schema
// ---------------------------------------------------------------------
// Multi-Tenant-SaaS für Elternvereine. Tenant = `Kita`.
//
// Sicherheits-Leitplanken (siehe planung.md §5):
//  • Jedes mandantengebundene Modell trägt `kitaId` und ist über
//    `Kita` per `onDelete: Cascade` verknüpft → DSGVO-konformes
//    "Recht auf Vergessenwerden".
//  • Auf Applikations-/Server-Action-Ebene MUSS jeder Query mit
//    `where: { kitaId: session.user.kitaId }` versehen werden.
//  • Keine Soft-Deletes auf personenbezogene Daten.
// =====================================================================

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

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

// =====================================================================
// ENUMS
// =====================================================================

/// Rollen-basierte Zugriffskontrolle (RBAC).
/// SUPERADMIN existiert systemweit (kitaId optional);
/// ADMIN, KOORDINATOR und ELTERN sind immer einer Kita zugeordnet.
enum UserRole {
  SUPERADMIN
  ADMIN
  KOORDINATOR
  ERZIEHER
  ELTERN
}

enum InvitationStatus {
  PENDING
  ACCEPTED
  EXPIRED
  REVOKED
}

enum TerminType {
  KITA_FEST
  SCHLIESSTAG
  TEAMTAG
  MITMACH_TAG
  ELTERNABEND
  MITGLIEDERVERSAMMLUNG
  ELTERNCAFE
  GEBURTSTAG_INTERN
  GEBURTSTAG_EXTERN
  SONSTIGES
}

enum TerminStatus {
  PENDING
  CONFIRMED
  REJECTED
  CANCELLED
}

enum EventParticipationStatus {
  ATTENDING
  NOT_ATTENDING
}

enum AuditTargetType {
  KITA
  USER
}

enum NotdienstPlanStatus {
  DRAFT
  PUBLISHED
}

enum NotdienstAlertStatus {
  PENDING
  CONFIRMED
  CANCELLED
}

enum DutyAssignmentStatus {
  PLANNED
  DONE
  CANCELLED
}

enum AbsenceReason {
  ILLNESS
  VACATION
  OTHER
}

// =====================================================================
// TENANT
// =====================================================================

model Kita {
  id   String @id @default(cuid())
  name String
  slug String @unique

  // Modul-Aktivierung (Einrichtungs-Wizard, Modul 0)
  notdienstModuleEnabled  Boolean @default(true)
  terminModuleEnabled     Boolean @default(true)
  adressbuchModuleEnabled Boolean @default(true)

  // Mandantenspezifische Regeln
  notdienstMinPerChildPerMonth Int @default(2)
  notdienstReminderDaysBefore  Int @default(7)

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

  // Relations (Cascade auf alle Tenant-Daten)
  users                   User[]
  families                Family[]
  children                Child[]
  educators               Educator[]
  parentDuties            ParentDuty[]
  parentDutyAssignments   ParentDutyAssignment[]
  dutyTypes               DutyType[]
  dutyAssignments         DutyAssignment[]
  absences                Absence[]
  announcements           Announcement[]
  invitations             Invitation[]
  termine                 Termin[]
  mitbringselItems        MitbringselItem[]
  eventParticipations     EventParticipation[]
  notdienstPlans          NotdienstPlan[]
  notdienstAvailabilities NotdienstAvailability[]
  notdienstAssignments    NotdienstAssignment[]
  notdienstAlerts         NotdienstAlert[]

  @@map("kitas")
}

// =====================================================================
// FAMILIES / HAUSHALTE
// =====================================================================

model Family {
  id String @id @default(cuid())

  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  name String

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

  users           User[]
  children        Child[]
  dutyAssignments DutyAssignment[]

  @@index([kitaId])
  @@map("families")
}

// =====================================================================
// USERS
// =====================================================================

model User {
  id String @id @default(cuid())

  /// Mandantenzuordnung. Nullable nur für `SUPERADMIN`.
  /// Bei Löschung der Kita werden alle zugeordneten User kaskadiert.
  kitaId String?
  kita   Kita?   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  /// Optional, weil Admins/Superadmins keinem Haushalt angehören müssen.
  /// Eltern-User werden beim Löschen ihrer Familie kaskadiert entfernt.
  familyId String?
  family   Family? @relation(fields: [familyId], references: [id], onDelete: Cascade)

  email        String @unique
  passwordHash String

  firstName String
  lastName  String

  role UserRole @default(ELTERN)

  // Adressbuch / Kontaktdaten (nur sichtbar bei directoryOptIn)
  phone      String?
  street     String?
  postalCode String?
  city       String?

  // ---- DSGVO Consent Logging (planung.md §5.2) ----
  /// Zeitstempel der Annahme der Datenschutzerklärung.
  /// Ohne diesen Wert blockiert die App den Zugriff (Redirect → Onboarding).
  privacyPolicyAcceptedAt DateTime?
  /// Versionsstring der akzeptierten Datenschutzerklärung (z.B. "2025-04-01").
  privacyPolicyVersion    String?
  /// Zeitstempel des Opt-Ins für das interne Kita-Adressbuch (Modul 3).
  directoryOptInAt        DateTime?

  // Auth-Bookkeeping
  emailVerifiedAt     DateTime?
  lastLoginAt         DateTime?
  failedLoginAttempts Int       @default(0)
  lockedUntil         DateTime?

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

  // Relations
  dutyAssignments ParentDutyAssignment[]

  notdienstAvailabilities  NotdienstAvailability[]
  notdienstAlertsAssigned  NotdienstAlert[]        @relation("NotdienstAlertParent")
  notdienstAlertsTriggered NotdienstAlert[]        @relation("NotdienstAlertTrigger")
  notdienstPlansCreated    NotdienstPlan[]         @relation("NotdienstPlanCreator")
  announcementsAuthored    Announcement[]          @relation("AnnouncementAuthor")
  announcementReads        AnnouncementRead[]

  termineCreated  Termin[] @relation("TerminCreator")
  termineApproved Termin[] @relation("TerminApprover")

  mitbringselItems   MitbringselItem[]
  invitationsCreated Invitation[]      @relation("InvitationCreator")
  auditLogsAuthored  AuditLog[]        @relation("AuditLogActor")

  @@index([kitaId])
  @@index([familyId])
  @@index([kitaId, role])
  @@map("users")
}

// =====================================================================
// CHILDREN
// =====================================================================

model Child {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  familyId String
  family   Family @relation(fields: [familyId], references: [id], onDelete: Cascade)

  firstName   String
  lastName    String
  dateOfBirth DateTime?
  notes       String?

  active Boolean @default(true)

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

  notdienstAvailabilities NotdienstAvailability[]
  notdienstAssignments    NotdienstAssignment[]
  absences                Absence[]
  eventParticipations     EventParticipation[]

  @@index([kitaId])
  @@index([familyId])
  @@map("children")
}

// =====================================================================
// EDUCATORS (ErzieherInnen — reine Stammdaten, keine Logins, Modul 4)
// =====================================================================

model Educator {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  firstName String
  lastName  String
  active    Boolean @default(true)

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

  notdienstAlerts NotdienstAlert[]

  @@index([kitaId])
  @@map("educators")
}

// =====================================================================
// PARENT DUTIES (Feste Ämter / Elterndienste, Modul 3)
// =====================================================================

model ParentDuty {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  name        String
  description String?
  active      Boolean @default(true)

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

  assignments ParentDutyAssignment[]

  @@unique([kitaId, name])
  @@index([kitaId])
  @@map("parent_duties")
}

model ParentDutyAssignment {
  id     String     @id @default(cuid())
  kitaId String
  kita   Kita       @relation(fields: [kitaId], references: [id], onDelete: Cascade)
  dutyId String
  duty   ParentDuty @relation(fields: [dutyId], references: [id], onDelete: Cascade)
  userId String
  user   User       @relation(fields: [userId], references: [id], onDelete: Cascade)

  createdAt DateTime @default(now())

  @@unique([dutyId, userId])
  @@index([kitaId])
  @@index([userId])
  @@map("parent_duty_assignments")
}

// =====================================================================
// DUTY PLANNING (Top-Down-Dienstplan fuer Haushalte)
// =====================================================================

model DutyType {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  name        String
  description String?

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

  assignments DutyAssignment[]

  @@unique([kitaId, name])
  @@index([kitaId])
  @@map("duty_types")
}

model DutyAssignment {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  familyId String
  family   Family @relation(fields: [familyId], references: [id], onDelete: Cascade)

  dutyTypeId String
  dutyType   DutyType @relation(fields: [dutyTypeId], references: [id], onDelete: Cascade)

  startDate DateTime             @db.Date
  endDate   DateTime             @db.Date
  status    DutyAssignmentStatus @default(PLANNED)

  reminderSentAt DateTime?

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

  @@unique([kitaId, dutyTypeId, startDate])
  @@index([kitaId, startDate])
  @@index([familyId, startDate])
  @@map("duty_assignments")
}

// =====================================================================
// ABSENCES (Abwesenheits- und Krankmeldungen)
// =====================================================================

model Absence {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  childId String
  child   Child  @relation(fields: [childId], references: [id], onDelete: Cascade)

  startDate DateTime      @db.Date
  endDate   DateTime      @db.Date
  reason    AbsenceReason
  note      String?

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

  @@index([kitaId, startDate, endDate])
  @@index([childId, startDate])
  @@map("absences")
}

// =====================================================================
// ANNOUNCEMENTS (Digitales Schwarzes Brett)
// =====================================================================

model Announcement {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  title   String
  content String

  authorId String
  author   User   @relation("AnnouncementAuthor", fields: [authorId], references: [id], onDelete: Cascade)

  createdAt DateTime @default(now())

  attachments Attachment[]
  reads       AnnouncementRead[]

  @@index([kitaId, createdAt])
  @@index([authorId])
  @@map("announcements")
}

model Attachment {
  id             String       @id @default(cuid())
  announcementId String
  announcement   Announcement @relation(fields: [announcementId], references: [id], onDelete: Cascade)

  fileName String
  fileUrl  String
  fileType String

  @@index([announcementId])
  @@map("attachments")
}

model AnnouncementRead {
  id             String       @id @default(cuid())
  userId         String
  user           User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  announcementId String
  announcement   Announcement @relation(fields: [announcementId], references: [id], onDelete: Cascade)

  readAt DateTime @default(now())

  @@unique([userId, announcementId])
  @@index([announcementId])
  @@map("announcement_reads")
}

// =====================================================================
// INVITATIONS (Invite-Only Onboarding, Modul 3)
// =====================================================================

model Invitation {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  email String
  role  UserRole @default(ELTERN)

  token      String           @unique
  status     InvitationStatus @default(PENDING)
  expiresAt  DateTime
  acceptedAt DateTime?

  invitedById String?
  invitedBy   User?   @relation("InvitationCreator", fields: [invitedById], references: [id], onDelete: SetNull)

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

  @@unique([kitaId, email])
  @@index([kitaId])
  @@map("invitations")
}

// =====================================================================
// TERMINE (Kalender, Modul 2)
// =====================================================================

model Termin {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  title       String
  description String?
  type        TerminType
  status      TerminStatus @default(PENDING)

  startDate DateTime
  endDate   DateTime
  allDay    Boolean  @default(false)

  /// Mitbringliste pro Termin aktivierbar (Modul 2, "Flexible Mitbring-Listen")
  mitbringselListEnabled Boolean @default(false)

  /// Teilnahme-Abfrage für Ausflüge und besondere Events.
  requiresRsvp    Boolean   @default(false)
  rsvpDeadline    DateTime?
  participantInfo String?

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

  approvedById    String?
  approvedBy      User?     @relation("TerminApprover", fields: [approvedById], references: [id], onDelete: SetNull)
  approvedAt      DateTime?
  rejectionReason String?

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

  mitbringselItems MitbringselItem[]
  participations   EventParticipation[]

  @@index([kitaId, startDate])
  @@index([kitaId, status])
  @@map("termine")
}

model EventParticipation {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  eventId String
  event   Termin @relation(fields: [eventId], references: [id], onDelete: Cascade)

  childId String
  child   Child  @relation(fields: [childId], references: [id], onDelete: Cascade)

  status EventParticipationStatus

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

  @@unique([eventId, childId])
  @@index([kitaId])
  @@index([childId])
  @@map("event_participations")
}

model MitbringselItem {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  terminId String
  termin   Termin @relation(fields: [terminId], references: [id], onDelete: Cascade)

  /// Cascade: Beim Löschen eines Accounts werden dessen Mitbringsel-Einträge
  /// rückstandslos mitgelöscht (DSGVO "Recht auf Vergessenwerden").
  userId String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)

  content String

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

  @@index([kitaId])
  @@index([terminId])
  @@map("mitbringsel_items")
}

// =====================================================================
// NOTDIENST (Modul 1 – Kern-Feature)
// =====================================================================

/// Monatlicher Notdienst-Plan. Erst DRAFT (Koordinator bearbeitet),
/// nach "Veröffentlichung" PUBLISHED.
model NotdienstPlan {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  year   Int
  /// Monat 1–12.
  month  Int
  status NotdienstPlanStatus @default(DRAFT)

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

  publishedAt DateTime?

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

  assignments NotdienstAssignment[]

  @@unique([kitaId, year, month])
  @@index([kitaId])
  @@map("notdienst_plans")
}

/// Verfügbarkeits-Eintrag eines Elternteils für ein Kind an einem Tag.
/// Pro (Kind, Datum) maximal ein Eintrag — Geschwister-Doppelbuchungen
/// werden über die App-Logik geblockt.
model NotdienstAvailability {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  childId String
  child   Child  @relation(fields: [childId], references: [id], onDelete: Cascade)

  /// Eintragender User (für Audit / Erinnerungs-Cronjob).
  userId String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)

  date DateTime @db.Date

  createdAt DateTime @default(now())

  @@unique([childId, date])
  @@index([kitaId, date])
  @@index([userId])
  @@map("notdienst_availabilities")
}

/// Eingeteilter Notdienst-Slot — Ergebnis der Plan-Generierung
/// bzw. manueller Bearbeitung durch den Koordinator.
model NotdienstAssignment {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  planId String
  plan   NotdienstPlan @relation(fields: [planId], references: [id], onDelete: Cascade)

  childId String
  child   Child  @relation(fields: [childId], references: [id], onDelete: Cascade)

  date DateTime @db.Date

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

  alerts NotdienstAlert[]

  @@unique([planId, date])
  @@index([kitaId, date])
  @@map("notdienst_assignments")
}

/// Aktive Alarmierung — wird bei Krankmeldung einer Fachkraft
/// vom Koordinator ausgelöst. Bestätigung via Magic-Link (Token).
model NotdienstAlert {
  id     String @id @default(cuid())
  kitaId String
  kita   Kita   @relation(fields: [kitaId], references: [id], onDelete: Cascade)

  assignmentId String
  assignment   NotdienstAssignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)

  /// Eingeteiltes Elternteil (Empfänger des Alarms).
  parentUserId String
  parentUser   User   @relation("NotdienstAlertParent", fields: [parentUserId], references: [id], onDelete: Cascade)

  /// Auslösender Koordinator.
  triggeredById String?
  triggeredBy   User?   @relation("NotdienstAlertTrigger", fields: [triggeredById], references: [id], onDelete: SetNull)

  /// Optional: kranke Fachkraft (Referenz für Reporting).
  educatorId String?
  educator   Educator? @relation(fields: [educatorId], references: [id], onDelete: SetNull)

  status NotdienstAlertStatus @default(PENDING)

  /// Einmal-Token für den Bestätigungslink in der Alarm-Mail.
  confirmationToken String    @unique
  triggeredAt       DateTime  @default(now())
  confirmedAt       DateTime?

  notes String?

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

  @@index([kitaId])
  @@index([assignmentId])
  @@index([parentUserId])
  @@map("notdienst_alerts")
}

// =====================================================================
// AUDIT LOGS (Systemweite Superadmin-Aktionen)
// =====================================================================

/// Persistente Spur fuer Superadmin-Support-Aktionen.
/// Zielobjekte werden bewusst nur als Snapshot gespeichert, damit Logs auch
/// nach einer Kita- oder Benutzerloeschung erhalten bleiben.
model AuditLog {
  id String @id @default(cuid())

  actorUserId String?
  actorUser   User?   @relation("AuditLogActor", fields: [actorUserId], references: [id], onDelete: SetNull)
  actorEmail  String

  action     String
  targetType AuditTargetType
  targetId   String
  targetLabel String
  targetKitaId String?

  metadata Json?
  createdAt DateTime @default(now())

  @@index([actorUserId])
  @@index([targetType, targetId])
  @@index([targetKitaId])
  @@index([createdAt])
  @@map("audit_logs")
}

// =====================================================================
// AUTH-HILFSTABELLE
// =====================================================================

/// Tokens für Passwort-Reset und E-Mail-Verifikation.
/// Kompatibel mit dem NextAuth-Schema, falls später Email-Provider aktiviert wird.
model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
  @@map("verification_tokens")
}
