generator client {
  provider      = "prisma-client-js"
  output     = "../src/generated/prisma"
  binaryTargets = ["native", "windows", "debian-openssl-3.0.x"]
}

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

enum UserRole {
  OWNER
  ADMIN
  STAFF
  TENANT
}

enum Gender {
  MALE
  FEMALE
  OTHER
}

enum RoomStatus {
  AVAILABLE
  RESERVED
  OCCUPIED
  MAINTENANCE
  INACTIVE
}

enum PricingTerm {
  DAILY
  WEEKLY
  BIWEEKLY
  MONTHLY
  SMESTERLY
  YEARLY
}

enum StayStatus {
  ACTIVE
  COMPLETED
  CANCELLED
}

enum DepositStatus {
  HELD
  PARTIALLY_REFUNDED
  REFUNDED
  FORFEITED
}

enum UtilityType {
  ELECTRICITY
  WATER
}

enum InvoiceStatus {
  DRAFT
  ISSUED
  PARTIAL
  PAID
  CANCELLED
}

enum InvoiceLineType {
  RENT
  ELECTRICITY
  WATER
  PENALTY
  DISCOUNT
  WIFI
  OTHER
}

enum PaymentMethod {
  CASH
  TRANSFER
  QRIS
  EWALLET
  OTHER
}

enum PaymentSubmissionStatus {
  PENDING_REVIEW
  APPROVED
  REJECTED
  EXPIRED
}

enum TicketStatus {
  OPEN
  IN_PROGRESS
  DONE
  CLOSED
  CANCELLED
}

enum RoomItemStatus {
  GOOD
  DAMAGED
  MAINTENANCE
  MISSING
}

enum InventoryMovementType {
  IN
  OUT
  ASSIGN_TO_ROOM
  RETURN_FROM_ROOM
  ADJUSTMENT
}

enum AnnouncementAudience {
  TENANT
  ALL
}

enum LeadSource {
  GOOGLE_MAPS
  WALK_IN
  REFERRAL
  INSTAGRAM
  TIKTOK
  WHATSAPP
  FACEBOOK
  WEBSITE
  OTA
  OTHER
}

enum StayPurpose {
  WORK
  STUDY
  TRANSIT
  FAMILY
  MEDICAL
  PROJECT
  OTHER
}

enum ExpenseType {
  FIXED
  VARIABLE
}

enum ExpenseCategory {
  RENT_BUILDING
  SALARY
  ELECTRICITY
  WATER
  INTERNET
  MAINTENANCE
  CLEANING
  SUPPLIES
  TAX
  MARKETING
  OTHER
}

model User {
  id           Int       @id @default(autoincrement())
  fullName     String
  email        String    @unique
  passwordHash String
  role         UserRole
  tenantId     Int?      @unique
  isActive     Boolean   @default(true)
  lastLoginAt  DateTime?
  createdAt    DateTime  @default(now())
  updatedAt    DateTime  @updatedAt

  tenant                    Tenant?              @relation(fields: [tenantId], references: [id], onDelete: SetNull)
  announcementsCreated      Announcement[]       @relation("AnnouncementCreatedBy")
  staysCreated              Stay[]               @relation("StayCreatedBy")
  invoicesCreated           Invoice[]            @relation("InvoiceCreatedBy")
  paymentsCaptured          InvoicePayment[]     @relation("InvoicePaymentCapturedBy")
  ticketsAssigned           Ticket[]             @relation("TicketAssignedTo")
  meterReadingsRecorded     MeterReading[]       @relation("MeterReadingRecordedBy")
  inventoryMovementsCreated InventoryMovement[]  @relation("InventoryMovementCreatedBy")
  wifiSalesCreated          WifiSale[]           @relation("WifiSaleCreatedBy")
  expensesCreated           Expense[]            @relation("ExpenseCreatedBy")
  auditLogs                 AuditLog[]           @relation("AuditLogActor")

  @@index([role])
  @@index([isActive])
}

model Tenant {
  id                    Int       @id @default(autoincrement())
  fullName              String
  phone                 String
  email                 String?
  identityNumber        String?

  gender                Gender?
  birthDate             DateTime?
  originCity            String?
  occupation            String?
  companyOrCampus       String?

  emergencyContactName  String?
  emergencyContactPhone String?
  notes                 String?
  isActive              Boolean   @default(true)
  createdAt             DateTime  @default(now())
  updatedAt             DateTime  @updatedAt

  user    User?
  stays   Stay[]
  tickets Ticket[]

  @@index([fullName])
  @@index([phone])
  @@index([email])
  @@index([gender])
  @@index([originCity])
  @@index([occupation])
  @@index([companyOrCampus])
  @@index([isActive])
}

model Room {
  id                            Int        @id @default(autoincrement())
  code                          String     @unique
  name                          String?
  floor                         String?
  status                        RoomStatus @default(AVAILABLE)

  dailyRateRupiah               Int?
  weeklyRateRupiah              Int?
  biWeeklyRateRupiah            Int?
  monthlyRateRupiah             Int

  defaultDepositRupiah          Int        @default(0)
  electricityTariffPerKwhRupiah Int        @default(0)
  waterTariffPerM3Rupiah        Int        @default(0)

  notes                         String?
  isActive                      Boolean    @default(true)
  createdAt                     DateTime   @default(now())
  updatedAt                     DateTime   @updatedAt

  stays         Stay[]
  meterReadings MeterReading[]
  tickets       Ticket[]
  roomItems     RoomItem[]
  expenses      Expense[]
  inventoryMovements InventoryMovement[]

  @@index([status])
  @@index([isActive])
}

model Stay {
  id                            Int           @id @default(autoincrement())
  tenantId                      Int
  roomId                        Int
  status                        StayStatus    @default(ACTIVE)

  pricingTerm                   PricingTerm
  agreedRentAmountRupiah        Int

  checkInDate                   DateTime      @db.Date
  plannedCheckOutDate           DateTime?     @db.Date
  actualCheckOutDate            DateTime?     @db.Date
  expiresAt                    DateTime?

  depositAmountRupiah           Int           @default(0)
  depositStatus                 DepositStatus @default(HELD)
  depositDeductionRupiah        Int           @default(0)
  depositRefundedRupiah         Int           @default(0)
  depositRefundedAt             DateTime?
  depositNote                   String?

  electricityTariffPerKwhRupiah Int           @default(0)
  waterTariffPerM3Rupiah        Int           @default(0)

  bookingSource                 LeadSource?
  bookingSourceDetail           String?
  stayPurpose                   StayPurpose?
  checkoutReason                String?

  notes                         String?
  createdById                   Int?
  createdAt                     DateTime      @default(now())
  updatedAt                     DateTime      @updatedAt

  tenant    Tenant  @relation(fields: [tenantId], references: [id], onDelete: Restrict)
  room      Room    @relation(fields: [roomId], references: [id], onDelete: Restrict)
  createdBy User?   @relation("StayCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)

  invoices  Invoice[]
  tickets   Ticket[]
  expenses  Expense[]

  @@index([tenantId])
  @@index([roomId])
  @@index([status])
  @@index([tenantId, status])
  @@index([roomId, status])
  @@index([checkInDate])
  @@index([expiresAt])
  @@index([bookingSource])
  @@index([stayPurpose])
}

model MeterReading {
  id           Int         @id @default(autoincrement())
  roomId       Int
  utilityType  UtilityType
  readingAt    DateTime
  readingValue Decimal     @db.Decimal(12, 3)
  note         String?
  recordedById Int?
  createdAt    DateTime    @default(now())

  room       Room   @relation(fields: [roomId], references: [id], onDelete: Restrict)
  recordedBy User?  @relation("MeterReadingRecordedBy", fields: [recordedById], references: [id], onDelete: SetNull)

  @@unique([roomId, utilityType, readingAt])
  @@index([roomId, utilityType])
  @@index([readingAt])
}

model Invoice {
  id                Int           @id @default(autoincrement())
  invoiceNumber     String        @unique
  stayId            Int
  status            InvoiceStatus @default(DRAFT)
  periodStart       DateTime      @db.Date
  periodEnd         DateTime      @db.Date
  issuedAt          DateTime?
  dueDate           DateTime?     @db.Date
  paidAt            DateTime?
  totalAmountRupiah Int           @default(0)
  notes             String?
  cancelReason      String?
  createdById       Int?
  createdAt         DateTime      @default(now())
  updatedAt         DateTime      @updatedAt

  stay      Stay   @relation(fields: [stayId], references: [id], onDelete: Restrict)
  createdBy User?  @relation("InvoiceCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)

  lines     InvoiceLine[]
  payments  InvoicePayment[]

  @@index([stayId])
  @@index([status])
  @@index([periodStart, periodEnd])
  @@index([dueDate])
}

model InvoiceLine {
  id               Int             @id @default(autoincrement())
  invoiceId        Int
  lineType         InvoiceLineType
  utilityType      UtilityType?
  description      String
  qty              Decimal         @default(1) @db.Decimal(12, 2)
  unit             String?
  unitPriceRupiah  Int
  lineAmountRupiah Int
  sortOrder        Int             @default(0)
  createdAt        DateTime        @default(now())
  updatedAt        DateTime        @updatedAt

  invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)

  @@index([invoiceId])
  @@index([lineType])
  @@index([utilityType])
  @@index([invoiceId, sortOrder])
}

model InvoicePayment {
  id            Int           @id @default(autoincrement())
  invoiceId     Int
  paymentDate   DateTime      @db.Date
  amountRupiah  Int
  method        PaymentMethod
  referenceNo   String?
  note          String?
  capturedById  Int?
  createdAt     DateTime      @default(now())
  updatedAt     DateTime      @updatedAt

  invoice    Invoice @relation(fields: [invoiceId], references: [id], onDelete: Restrict)
  capturedBy User?   @relation("InvoicePaymentCapturedBy", fields: [capturedById], references: [id], onDelete: SetNull)

  @@index([invoiceId])
  @@index([paymentDate])
}


model PaymentSubmission {
  id               Int                     @id @default(autoincrement())
  stayId           Int
  invoiceId        Int
  tenantId         Int
  submittedById    Int
  amountRupiah     Int
  paidAt           DateTime                @db.Date
  paymentMethod    PaymentMethod
  senderName       String?
  senderBankName   String?
  referenceNumber  String?
  notes            String?
  fileKey          String?
  fileUrl          String?
  originalFilename String?
  mimeType         String?
  fileSizeBytes    Int?
  status           PaymentSubmissionStatus @default(PENDING_REVIEW)
  reviewedById     Int?
  reviewedAt       DateTime?
  reviewNotes      String?
  createdAt        DateTime                @default(now())
  updatedAt        DateTime                @updatedAt

  stay        Stay   @relation(fields: [stayId], references: [id], onDelete: Restrict)
  invoice     Invoice @relation(fields: [invoiceId], references: [id], onDelete: Restrict)
  tenant      Tenant @relation(fields: [tenantId], references: [id], onDelete: Restrict)
  submittedBy User   @relation("PaymentSubmissionSubmittedBy", fields: [submittedById], references: [id], onDelete: Restrict)
  reviewedBy  User?  @relation("PaymentSubmissionReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)

  @@index([stayId])
  @@index([invoiceId])
  @@index([tenantId])
  @@index([status])
  @@index([invoiceId, status])
}

model Ticket {
  id              Int          @id @default(autoincrement())
  ticketNumber    String       @unique
  tenantId        Int
  roomId          Int?
  stayId          Int?
  title           String
  description     String
  category        String?
  status          TicketStatus @default(OPEN)
  assignedToId    Int?
  resolutionNote  String?
  resolvedAt      DateTime?
  closedAt        DateTime?
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt

  tenant     Tenant @relation(fields: [tenantId], references: [id], onDelete: Restrict)
  room       Room?  @relation(fields: [roomId], references: [id], onDelete: SetNull)
  stay       Stay?  @relation(fields: [stayId], references: [id], onDelete: SetNull)
  assignedTo User?  @relation("TicketAssignedTo", fields: [assignedToId], references: [id], onDelete: SetNull)

  @@index([tenantId])
  @@index([roomId])
  @@index([stayId])
  @@index([status])
}

model Announcement {
  id          Int                  @id @default(autoincrement())
  title       String
  content     String
  audience    AnnouncementAudience @default(TENANT)
  isPublished Boolean              @default(false)
  isPinned    Boolean              @default(false)
  publishedAt DateTime?
  startsAt    DateTime?
  expiresAt   DateTime?
  createdById Int?
  createdAt   DateTime             @default(now())
  updatedAt   DateTime             @updatedAt

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

  @@index([audience])
  @@index([isPublished])
  @@index([isPinned])
  @@index([startsAt])
  @@index([expiresAt])
}

model InventoryItem {
  id          Int       @id @default(autoincrement())
  sku         String?   @unique
  name        String
  category    String?
  unit        String    @default("pcs")
  qtyOnHand   Decimal   @default(0) @db.Decimal(12, 2)
  minQty      Decimal   @default(0) @db.Decimal(12, 2)
  notes       String?
  isActive    Boolean   @default(true)
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt

  roomItems   RoomItem[]
  movements   InventoryMovement[]

  @@index([name])
  @@index([category])
  @@index([isActive])
}

model RoomItem {
  id         Int            @id @default(autoincrement())
  roomId     Int
  itemId     Int
  qty        Decimal        @default(1) @db.Decimal(12, 2)
  status     RoomItemStatus @default(GOOD)
  note       String?
  createdAt  DateTime       @default(now())
  updatedAt  DateTime       @updatedAt

  room Room          @relation(fields: [roomId], references: [id], onDelete: Cascade)
  item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)

  @@unique([roomId, itemId])
  @@index([roomId])
  @@index([itemId])
  @@index([status])
}

model InventoryMovement {
  id           Int                   @id @default(autoincrement())
  itemId        Int
  movementType  InventoryMovementType
  qty           Decimal              @db.Decimal(12, 2)
  roomId        Int?
  movementDate  DateTime             @db.Date
  note          String?
  createdById   Int?
  createdAt     DateTime             @default(now())

  item      InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
  room      Room?         @relation(fields: [roomId], references: [id], onDelete: SetNull)
  createdBy User?         @relation("InventoryMovementCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)

  @@index([itemId])
  @@index([roomId])
  @@index([movementDate])
  @@index([movementType])
}

model WifiSale {
  id              Int      @id @default(autoincrement())
  saleDate        DateTime @db.Date
  customerName    String
  packageName     String
  soldPriceRupiah Int
  note            String?
  createdById     Int?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

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

  @@index([saleDate])
  @@index([customerName])
}

model Expense {
  id            Int             @id @default(autoincrement())
  expenseDate   DateTime        @db.Date
  type          ExpenseType
  category      ExpenseCategory
  description   String
  amountRupiah  Int
  vendorName    String?
  roomId        Int?
  stayId        Int?
  note          String?
  createdById   Int?
  createdAt     DateTime        @default(now())
  updatedAt     DateTime        @updatedAt

  room      Room? @relation(fields: [roomId], references: [id], onDelete: SetNull)
  stay      Stay? @relation(fields: [stayId], references: [id], onDelete: SetNull)
  createdBy User? @relation("ExpenseCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)

  @@index([expenseDate])
  @@index([type])
  @@index([category])
  @@index([roomId])
  @@index([stayId])
}

model AuditLog {
  id          Int      @id @default(autoincrement())
  actorUserId Int?
  action      String
  entityType  String
  entityId    String?
  oldData     Json?
  newData     Json?
  meta        Json?
  createdAt   DateTime @default(now())

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

  @@index([actorUserId])
  @@index([entityType, entityId])
  @@index([createdAt])
}