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

// 兼容 seed 脚本在 Node.js 直接运行时使用 @prisma/client runtime。
generator seed_client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
}

// 角色枚举：用于鉴权与数据可见性控制。
enum Role {
  SYSTEM_ADMIN
  HOSPITAL_ADMIN
  DIRECTOR
  LEADER
  DOCTOR
  ENGINEER
}

// 设备状态枚举：表示设备是否处于使用中。
enum DeviceStatus {
  ACTIVE
  INACTIVE
}

// 任务状态枚举：定义任务流转状态机。
enum TaskStatus {
  PENDING
  ACCEPTED
  COMPLETED
  CANCELLED
}

// 医学字典类型：驱动患者手术表单中的单选/多选项。
enum DictionaryType {
  PRIMARY_DISEASE
  HYDROCEPHALUS_TYPE
  SHUNT_MODE
  PROXIMAL_PUNCTURE_AREA
  VALVE_PLACEMENT_SITE
  DISTAL_SHUNT_DIRECTION
}

// 上传资产类型：用于图库/视频库分类。
enum UploadAssetType {
  IMAGE
  VIDEO
  FILE
}

// 医院主表：多租户顶层实体。
model Hospital {
  id          Int           @id @default(autoincrement())
  name        String
  departments Department[]
  users       User[]
  patients    Patient[]
  tasks       Task[]
  uploads     UploadAsset[]
}

// 科室表：归属于医院。
model Department {
  id         Int      @id @default(autoincrement())
  name       String
  hospitalId Int
  hospital   Hospital @relation(fields: [hospitalId], references: [id])
  groups     Group[]
  users      User[]

  @@index([hospitalId])
}

// 小组表：归属于科室。
model Group {
  id           Int        @id @default(autoincrement())
  name         String
  departmentId Int
  department   Department @relation(fields: [departmentId], references: [id])
  users        User[]

  @@index([departmentId])
}

// 用户表：支持后台密码登录与小程序 openId。
// 同一个微信 openId 允许绑定多个院内账号，便于多角色/多院区切换。
model User {
  id               Int              @id @default(autoincrement())
  name             String
  phone            String
  // 后台登录密码哈希（bcrypt）。
  passwordHash     String?
  // 该时间点之前签发的 token 一律失效。
  tokenValidAfter  DateTime         @default(now())
  openId           String?
  role             Role
  hospitalId       Int?
  departmentId     Int?
  groupId          Int?
  hospital         Hospital?        @relation(fields: [hospitalId], references: [id])
  department       Department?      @relation(fields: [departmentId], references: [id])
  // 小组删除必须先清理成员，避免静默把用户 groupId 置空。
  group            Group?           @relation(fields: [groupId], references: [id], onDelete: Restrict)
  doctorPatients   Patient[]        @relation("DoctorPatients")
  createdPatients  Patient[]        @relation("PatientCreator")
  createdTasks     Task[]           @relation("TaskCreator")
  acceptedTasks    Task[]           @relation("TaskEngineer")
  surgeonSurgeries PatientSurgery[] @relation("SurgerySurgeon")
  createdUploads   UploadAsset[]    @relation("UploadCreator")

  @@unique([phone, role, hospitalId])
  @@index([phone])
  @@index([openId])
  @@index([hospitalId, role])
  @@index([departmentId, role])
  @@index([groupId, role])
}

// 家属小程序账号：按手机号承载 C 端登录身份，并预留服务号绑定字段。
model FamilyMiniAppAccount {
  id          Int      @id @default(autoincrement())
  phone       String   @unique
  openId      String?  @unique
  serviceUid  String?  @unique
  lastLoginAt DateTime @default(now())
  createdAt   DateTime @default(now())
  updatedAt   DateTime @default(now()) @updatedAt

  @@index([lastLoginAt])
}

// 患者表：院内患者档案，按医院隔离。
model Patient {
  id          Int              @id @default(autoincrement())
  name        String
  createdAt   DateTime         @default(now())
  // 住院号：用于院内患者检索与病案关联。
  inpatientNo String?
  // 项目名称：用于区分患者所属项目/课题。
  projectName String?
  phone       String
  // 患者身份证号，录入与查询都使用原始证件号。
  idCard      String
  hospitalId  Int
  doctorId    Int
  creatorId   Int
  hospital    Hospital         @relation(fields: [hospitalId], references: [id])
  doctor      User             @relation("DoctorPatients", fields: [doctorId], references: [id])
  creator     User             @relation("PatientCreator", fields: [creatorId], references: [id])
  surgeries   PatientSurgery[]
  devices     Device[]

  @@index([phone, idCard])
  @@index([hospitalId, doctorId])
  @@index([inpatientNo])
  @@index([creatorId])
}

// 患者手术表：保存每次分流/复手术档案。
model PatientSurgery {
  id                       Int       @id @default(autoincrement())
  patientId                Int
  surgeryDate              DateTime
  surgeryName              String
  surgeonId                Int?
  surgeonName              String
  // 术前测压：部分患者可为空。
  preOpPressure            Int?
  // 原发病：前端单选，后端先按字符串存储，方便后续补字典。
  primaryDisease           String
  // 脑积水类型：前端多选。
  hydrocephalusTypes       String[]  @default([])
  // 上次分流手术时间：无既往分流史时为空。
  previousShuntSurgeryDate DateTime?
  // 术前影像/资料：支持图片、视频等附件元数据。
  preOpMaterials           Json?
  notes                    String?
  createdAt                DateTime  @default(now())
  patient                  Patient   @relation(fields: [patientId], references: [id], onDelete: Cascade)
  surgeon                  User?     @relation("SurgerySurgeon", fields: [surgeonId], references: [id], onDelete: SetNull)
  devices                  Device[]

  @@index([patientId, surgeryDate])
  @@index([surgeonId])
}

// 植入物型号字典：供前端单选型号后自动回填厂家与名称。
model ImplantCatalog {
  id                   Int      @id @default(autoincrement())
  modelCode            String   @unique
  manufacturer         String
  name                 String
  // 是否为阀门；关闭时表示管子/附件，不提供压力挡位。
  isValve              Boolean  @default(true)
  // 可调压器械的可选挡位，由系统管理员维护。
  pressureLevels       String[] @default([])
  isPressureAdjustable Boolean  @default(true)
  notes                String?
  createdAt            DateTime @default(now())
  updatedAt            DateTime @default(now()) @updatedAt
  devices              Device[]
}

// 系统级字典项：由系统管理员维护，供患者手术表单选择使用。
model DictionaryItem {
  id        Int            @id @default(autoincrement())
  type      DictionaryType
  label     String
  sortOrder Int            @default(0)
  enabled   Boolean        @default(true)
  createdAt DateTime       @default(now())
  updatedAt DateTime       @updatedAt

  @@unique([type, label])
  @@index([type, enabled, sortOrder])
}

// 上传资产表：保存图片/视频/文件元数据，供图库与患者表单复用。
model UploadAsset {
  id           Int             @id @default(autoincrement())
  hospitalId   Int
  creatorId    Int
  type         UploadAssetType
  originalName String
  fileName     String
  storagePath  String          @unique
  url          String
  mimeType     String
  fileSize     Int
  createdAt    DateTime        @default(now())
  hospital     Hospital        @relation(fields: [hospitalId], references: [id])
  creator      User            @relation("UploadCreator", fields: [creatorId], references: [id])

  @@index([hospitalId, type, createdAt])
  @@index([creatorId, createdAt])
}

// 设备表：每次手术植入的设备实例，保留当前压力与历史调压记录。
model Device {
  id                    Int             @id @default(autoincrement())
  currentPressure       String
  status                DeviceStatus    @default(ACTIVE)
  patientId             Int
  surgeryId             Int?
  implantCatalogId      Int?
  // 植入物快照：避免型号字典修改后影响历史病历。
  implantModel          String?
  implantManufacturer   String?
  implantName           String?
  isValve               Boolean         @default(true)
  isPressureAdjustable  Boolean         @default(true)
  // 二次手术后旧设备可标记弃用，但历史调压任务仍需保留。
  isAbandoned           Boolean         @default(false)
  shuntMode             String?
  proximalPunctureAreas String[]        @default([])
  valvePlacementSites   String[]        @default([])
  distalShuntDirection  String?
  initialPressure       String?
  implantNotes          String?
  labelImageUrl         String?
  patient               Patient         @relation(fields: [patientId], references: [id])
  surgery               PatientSurgery? @relation(fields: [surgeryId], references: [id], onDelete: SetNull)
  implantCatalog        ImplantCatalog? @relation(fields: [implantCatalogId], references: [id], onDelete: SetNull)
  taskItems             TaskItem[]

  @@index([patientId, status])
  @@index([surgeryId])
  @@index([implantCatalogId])
  @@index([patientId, isAbandoned])
}

// 主任务表：记录调压任务主单。
model Task {
  id                  Int        @id @default(autoincrement())
  status              TaskStatus @default(PENDING)
  creatorId           Int
  engineerId          Int?
  hospitalId          Int
  createdAt           DateTime   @default(now())
  // 工程师完成任务时上传的图片/视频凭证。
  completionMaterials Json?
  creator             User       @relation("TaskCreator", fields: [creatorId], references: [id])
  engineer            User?      @relation("TaskEngineer", fields: [engineerId], references: [id])
  hospital            Hospital   @relation(fields: [hospitalId], references: [id])
  items               TaskItem[]

  @@index([hospitalId, status, createdAt])
}

// 任务明细表：一个任务可包含多个设备调压项。
model TaskItem {
  id             Int    @id @default(autoincrement())
  taskId         Int
  deviceId       Int
  oldPressure    String
  targetPressure String
  task           Task   @relation(fields: [taskId], references: [id], onDelete: Cascade)
  device         Device @relation(fields: [deviceId], references: [id])

  @@index([taskId])
  @@index([deviceId])
}
