// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider = "prisma-client-js"
  output   = "../generated/prisma"
}

generator zod {
  provider = "prisma-zod-generator"
  output   = "../shared/" // Zod schemas will be generated here inside `db/shared`
}

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

model User {
  id                   Int                   @id @default(autoincrement())
  username             String                @unique
  password             String
  patients             Patient[]
  appointments         Appointment[]
  staff                Staff[]
  claims               Claim[]
  insuranceCredentials InsuranceCredential[]
  updatedPayments      Payment[]             @relation("PaymentUpdatedBy")
  backups              DatabaseBackup[]
  notifications        Notification[]
  cloudFolders         CloudFolder[]
  cloudFiles           CloudFile[]
}

model Patient {
  id                Int           @id @default(autoincrement())
  firstName         String
  lastName          String
  dateOfBirth       DateTime      @db.Date
  gender            String
  phone             String
  email             String?
  address           String?
  city              String?
  zipCode           String?
  insuranceProvider String?
  insuranceId       String?
  groupNumber       String?
  policyHolder      String?
  allergies         String?
  medicalConditions String?
  status            String        @default("active")
  userId            Int
  createdAt         DateTime      @default(now())
  user              User          @relation(fields: [userId], references: [id])
  appointments      Appointment[]
  claims            Claim[]
  groups            PdfGroup[]
  payment           Payment[]

  @@index([insuranceId])
  @@index([createdAt])
}

model Appointment {
  id        Int      @id @default(autoincrement())
  patientId Int
  userId    Int
  staffId   Int
  title     String
  date      DateTime @db.Date
  startTime String // Store time as "hh:mm"
  endTime   String // Store time as "hh:mm"
  type      String // e.g., "checkup", "cleaning", "filling", etc.
  notes     String?
  status    String   @default("scheduled") // "scheduled", "completed", "cancelled", "no-show"
  createdAt DateTime @default(now())

  patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
  user    User    @relation(fields: [userId], references: [id])
  staff   Staff?  @relation(fields: [staffId], references: [id])
  claims  Claim[]

  @@index([patientId])
  @@index([date])
}

model Staff {
  id           Int           @id @default(autoincrement())
  userId       Int?
  name         String
  email        String?
  role         String // e.g., "Dentist", "Hygienist", "Assistant"
  phone        String?
  createdAt    DateTime      @default(now())
  user         User?         @relation(fields: [userId], references: [id], onDelete: Cascade)
  appointments Appointment[]
  claims       Claim[]       @relation("ClaimStaff")
}

model Claim {
  id                Int         @id @default(autoincrement())
  patientId         Int
  appointmentId     Int
  userId            Int
  staffId           Int
  patientName       String
  memberId          String
  dateOfBirth       DateTime    @db.Date
  remarks           String
  serviceDate       DateTime
  insuranceProvider String // e.g., "Delta MA"
  createdAt         DateTime    @default(now())
  updatedAt         DateTime    @updatedAt
  status            ClaimStatus @default(PENDING)

  patient     Patient     @relation(fields: [patientId], references: [id], onDelete: Cascade)
  appointment Appointment @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
  user        User?       @relation(fields: [userId], references: [id])
  staff       Staff?      @relation("ClaimStaff", fields: [staffId], references: [id])

  serviceLines ServiceLine[]
  claimFiles   ClaimFile[]
  payment      Payment?
}

enum ClaimStatus {
  PENDING
  APPROVED
  CANCELLED
  REVIEW
}

model ServiceLine {
  id             Int               @id @default(autoincrement())
  claimId        Int?
  paymentId      Int?
  procedureCode  String
  procedureDate  DateTime          @db.Date
  oralCavityArea String?
  toothNumber    String?
  toothSurface   String?
  totalBilled    Decimal           @db.Decimal(10, 2)
  totalPaid      Decimal           @default(0.00) @db.Decimal(10, 2)
  totalAdjusted  Decimal           @default(0.00) @db.Decimal(10, 2)
  totalDue       Decimal           @default(0.00) @db.Decimal(10, 2)
  status         ServiceLineStatus @default(UNPAID)

  claim   Claim?   @relation(fields: [claimId], references: [id], onDelete: Cascade)
  payment Payment? @relation(fields: [paymentId], references: [id], onDelete: Cascade)

  serviceLineTransactions ServiceLineTransaction[]
}

enum ServiceLineStatus {
  PENDING
  PARTIALLY_PAID
  PAID
  UNPAID
  ADJUSTED
  OVERPAID
  DENIED
}

model ClaimFile {
  id       Int    @id @default(autoincrement())
  claimId  Int
  filename String
  mimeType String

  claim Claim @relation(fields: [claimId], references: [id], onDelete: Cascade)
}

model InsuranceCredential {
  id       Int    @id @default(autoincrement())
  userId   Int
  siteKey  String
  username String
  password String

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

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

model PdfGroup {
  id        Int         @id @default(autoincrement())
  title     String
  titleKey  PdfTitleKey @default(OTHER)
  createdAt DateTime    @default(now())
  patientId Int
  patient   Patient     @relation(fields: [patientId], references: [id], onDelete: Cascade)
  pdfs      PdfFile[]

  @@index([patientId])
  @@index([titleKey])
}

model PdfFile {
  id         Int      @id @default(autoincrement())
  filename   String
  pdfData    Bytes
  uploadedAt DateTime @default(now())
  groupId    Int
  group      PdfGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)

  @@index([groupId])
}

enum PdfTitleKey {
  INSURANCE_CLAIM
  ELIGIBILITY_STATUS
  CLAIM_STATUS
  OTHER
}

model Payment {
  id            Int           @id @default(autoincrement())
  claimId       Int?          @unique
  patientId     Int
  userId        Int
  updatedById   Int?
  totalBilled   Decimal       @db.Decimal(10, 2)
  totalPaid     Decimal       @default(0.00) @db.Decimal(10, 2)
  totalAdjusted Decimal       @default(0.00) @db.Decimal(10, 2)
  totalDue      Decimal       @db.Decimal(10, 2)
  status        PaymentStatus @default(PENDING)
  notes         String?
  icn           String?
  createdAt     DateTime      @default(now())
  updatedAt     DateTime      @updatedAt

  claim                   Claim?                   @relation(fields: [claimId], references: [id], onDelete: Cascade)
  patient                 Patient                  @relation(fields: [patientId], references: [id], onDelete: Cascade)
  updatedBy               User?                    @relation("PaymentUpdatedBy", fields: [updatedById], references: [id])
  serviceLineTransactions ServiceLineTransaction[]
  serviceLines            ServiceLine[]

  @@index([claimId])
  @@index([patientId])
}

model ServiceLineTransaction {
  id             Int           @id @default(autoincrement())
  paymentId      Int
  serviceLineId  Int
  transactionId  String?
  paidAmount     Decimal       @db.Decimal(10, 2)
  adjustedAmount Decimal       @default(0.00) @db.Decimal(10, 2)
  method         PaymentMethod
  receivedDate   DateTime
  payerName      String?
  notes          String?
  createdAt      DateTime      @default(now())

  payment     Payment     @relation(fields: [paymentId], references: [id], onDelete: Cascade)
  serviceLine ServiceLine @relation(fields: [serviceLineId], references: [id], onDelete: Cascade)

  @@index([paymentId])
  @@index([serviceLineId])
}

enum PaymentStatus {
  PENDING
  PARTIALLY_PAID
  PAID
  OVERPAID
  DENIED
  VOID
}

enum PaymentMethod {
  EFT
  CHECK
  CASH
  CARD
  OTHER
}

model DatabaseBackup {
  id        Int      @id @default(autoincrement())
  userId    Int
  createdAt DateTime @default(now())

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

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

model Notification {
  id        Int               @id @default(autoincrement())
  userId    Int
  type      NotificationTypes
  message   String
  createdAt DateTime          @default(now())
  read      Boolean           @default(false)

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

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

enum NotificationTypes {
  BACKUP
  CLAIM
  PAYMENT
  ETC
}

model CloudFolder {
  id        Int           @id @default(autoincrement())
  userId    Int
  name      String
  parentId  Int?
  parent    CloudFolder?  @relation("FolderChildren", fields: [parentId], references: [id], onDelete: Cascade)
  children  CloudFolder[] @relation("FolderChildren")
  user      User          @relation(fields: [userId], references: [id])
  files     CloudFile[]
  createdAt DateTime      @default(now())
  updatedAt DateTime      @updatedAt

  @@unique([userId, parentId, name]) // prevents sibling folder name duplicates
  @@index([parentId])
}

model CloudFile {
  id          Int          @id @default(autoincrement())
  userId      Int
  name        String
  mimeType    String?
  fileSize    BigInt       @db.BigInt
  folderId    Int? // optional: null => root
  isComplete  Boolean      @default(false) // upload completed?
  totalChunks Int? // optional: expected number of chunks
  createdAt   DateTime     @default(now())
  updatedAt   DateTime     @updatedAt
  user        User         @relation(fields: [userId], references: [id])
  folder      CloudFolder? @relation(fields: [folderId], references: [id], onDelete: SetNull)

  chunks CloudFileChunk[]

  @@index([folderId])
}

model CloudFileChunk {
  id        Int      @id @default(autoincrement())
  fileId    Int
  seq       Int
  data      Bytes
  createdAt DateTime @default(now())

  file CloudFile @relation(fields: [fileId], references: [id], onDelete: Cascade)

  @@unique([fileId, seq])
  @@index([fileId, seq])
}
