// ============================================================================
// Prisma Schema — PT. Sarana Gemilang Finance System
// Stack: Node.js + Fastify + PostgreSQL + Prisma
// ============================================================================
//
// REVISI INI:
// - Tambah unique constraints di BtdDokumen, BdnDokumen, GudangDokumen
//   untuk cegah double input nomor dokumen
// - Tambah indexes untuk query yang sering dipakai (laporan bulanan,
//   filter statusPembayaran, lookup per klien)
// - Setelah apply schema ini, run: npx prisma generate && npx prisma migrate dev
// ============================================================================


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

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

// ─── Enums ───────────────────────────────────────────────────────────────────

enum Role {
  STAFF
  SUPERVISOR
  ADMIN
}

enum StatusDokumen {
  TERBUKA
  PROSES
  SELESAI
}

enum JenisTransaksi {
  FCL
  LCL
}

enum JenisLayanan {
  FCL_TPP_BTD
  FCL_TPP_BDN
  LCL_TPP_BTD
  LCL_TPP_BDN
  GUDANG_FCL
  GUDANG_LCL
  FULL_EKSPOR
  FULL_IMPOR
  KONSOLIDASI_FCL
  KONSOLIDASI_LCL
}

enum StatusInvoice {
  DRAFT
  TERBIT
  LUNAS
  BATAL
}

enum KategoriKlien {
  KLIEN
  EMKL
}

enum StatusPembayaran {
  BELUM_BAYAR
  SEBAGIAN
  LUNAS
  KADALUARSA
}

// ─── Users ───────────────────────────────────────────────────────────────────

model User {
  id           String   @id @default(cuid())
  nama         String
  email        String   @unique
  passwordHash String
  role         Role     @default(STAFF)
  aktif        Boolean  @default(true)
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  invoicesDibuat   Invoice[]     @relation("InvoiceCreatedBy")
  invoicesDihapus  Invoice[]     @relation("InvoiceDeletedBy")
  auditLogs        AuditLog[]
  refreshTokens    RefreshToken[]

  @@map("users")
}

model RefreshToken {
  id        String   @id @default(cuid())
  token     String   @unique
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  expiresAt DateTime
  createdAt DateTime @default(now())

  @@index([expiresAt])  // ← BARU: untuk cron cleanup
  @@map("refresh_tokens")
}

// ─── Klien ───────────────────────────────────────────────────────────────────

model Klien {
  id           String  @id @default(cuid())
  kode         String  @unique
  nama         String
  alamat       String?
  npwp         String?
  telepon      String?
  email        String?
  freeTimeDays Int?   // LEGACY — digantikan freeTimeTpp & freeTimeGudang. Dipertahankan untuk backward compat.
  // REV-4: Free time terpisah per kategori layanan
  freeTimeTpp    Int?   // Default 1 hari. Jika null, gunakan 1.
  freeTimeGudang Int?   // Default 5 hari. Jika null, gunakan 5.
  kategori     KategoriKlien @default(KLIEN)
  aktif        Boolean @default(true)

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

  tarifKhusus TarifKhusus[]
  btdDokumen  BtdDokumen[]
  bdnDokumen  BdnDokumen[]
  invoices    Invoice[]
  konsolidasiDokumen KonsolidasiDokumen[]
  gudangDokumen      GudangDokumen[]

  @@index([nama])  // ← BARU: untuk search by nama
  @@index([aktif]) // ← BARU: untuk filter klien aktif
  @@map("klien")
}

// ─── Tarif ───────────────────────────────────────────────────────────────────

model TarifGlobal {
  id         String   @id @default(cuid())
  kategori   String
  field      String
  nilai      Decimal  @db.Decimal(15, 2)
  keterangan String?
  updatedAt  DateTime @updatedAt
  updatedBy  String?

  @@unique([kategori, field])
  @@map("tarif_global")
}

model TarifKhusus {
  id       String  @id @default(cuid())
  klienId  String
  klien    Klien   @relation(fields: [klienId], references: [id])
  kategori String
  field    String
  nilai    Decimal @db.Decimal(15, 2)
  catatan  String?

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

  @@unique([klienId, kategori, field])
  @@map("tarif_khusus")
}

// ─── BTD Dokumen ─────────────────────────────────────────────────────────────

model BtdDokumen {
  id               String         @id @default(cuid())
  nomorBcf         String
  tanggalBcf       DateTime?
  nomorBc11        String?
  tanggalBc11      DateTime?
  posBc11          String?
  saranaPengangkut String?
  pemilikBarang    String
  klienId          String?
  klien            Klien?         @relation(fields: [klienId], references: [id])
  jumlahJenisKemasan String?
  uraianBarang     String?
  tppTujuan        String         @default("PT. Sarana Gemilang")
  jenisTransaksi   JenisTransaksi
  status           StatusDokumen  @default(TERBUKA)
  containers       Json           @default("[]")

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  createdBy String?

  invoices Invoice[]

  // ── BARU: Unique kombinasi nomorBcf + tanggalBcf ──
  // Cegah double-input dokumen dengan nomor BCF yang sama di tanggal yang sama.
  // Pakai compound key karena nomor BCF bisa terulang lintas tahun (sequence reset).
  @@unique([nomorBcf, tanggalBcf])

  @@index([nomorBcf])
  @@index([pemilikBarang])
  @@index([status])
  @@index([createdAt])  // ← BARU: untuk pagination by tanggal
  @@map("btd_dokumen")
}

// ─── BDN Dokumen ─────────────────────────────────────────────────────────────

model BdnDokumen {
  id                  String         @id @default(cuid())
  nomorKepBdn         String         @unique  // ← BARU: unique global karena format KEP-xxx/KBC.yyyy/zzz sudah include tahun
  tanggalKepBdn       DateTime?
  nomorPib            String?
  tanggalPib          DateTime?
  nomorPersetujuan    String?
  tanggalPersetujuan  DateTime?
  pemilikBarang       String
  klienId             String?
  klien               Klien?         @relation(fields: [klienId], references: [id])
  jumlahJenisKemasan  String?
  uraianBarang        String?
  tppTujuan           String         @default("PT. Sarana Gemilang")
  jenisTransaksi      JenisTransaksi
  status              StatusDokumen  @default(TERBUKA)
  containers          Json           @default("[]")

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  createdBy String?

  invoices Invoice[]

  @@index([pemilikBarang])
  @@index([status])
  @@index([createdAt])  // ← BARU
  @@map("bdn_dokumen")
}

// ─── Gudang Dokumen ───────────────────────────────────────────────────────────

model GudangDokumen {
  id             String         @id @default(cuid())
  blNomor        String
  consignee      String
  klienId        String?
  klien          Klien?         @relation(fields: [klienId], references: [id])
  party          String?
  jenisTransaksi JenisTransaksi
  status         StatusDokumen  @default(TERBUKA)
  catatan        String?

  nomorHBL       String?
  cbm            Decimal?       @db.Decimal(10, 3)
  tglMasuk       DateTime?
  tglKeluar      DateTime?

  containers     Json           @default("[]")
  pengeluaran    Json           @default("[]")

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  createdBy String?

  invoices Invoice[]

  // ── BARU: Unique kombinasi blNomor + consignee ──
  // BL bisa terulang antar shipment, tapi BL+Consignee yang sama = duplicate
  @@unique([blNomor, consignee])

  @@index([blNomor])
  @@index([consignee])
  @@index([status])
  @@index([createdAt])  // ← BARU
  @@map("gudang_dokumen")
}

// ─── Invoice ─────────────────────────────────────────────────────────────────

model Invoice {
  id             String        @id @default(cuid())
  nomorKW        String        @unique
  tahun          Int
  bulan          Int
  sequence       Int

  tanggalInvoice DateTime
  jenisLayanan   JenisLayanan
  tujuan         String?

  btdDokumenId    String?
  btdDokumen      BtdDokumen?    @relation(fields: [btdDokumenId],    references: [id])
  bdnDokumenId    String?
  bdnDokumen      BdnDokumen?    @relation(fields: [bdnDokumenId],    references: [id])
  gudangDokumenId String?
  gudangDokumen   GudangDokumen? @relation(fields: [gudangDokumenId], references: [id])
  konsolidasiDokumenId String?
  konsolidasiDokumen   KonsolidasiDokumen? @relation(fields: [konsolidasiDokumenId], references: [id])

  klienId    String?
  klien      Klien?  @relation(fields: [klienId], references: [id])
  consignee  String

  subTotal   Decimal @db.Decimal(15, 2)
  ppn        Decimal @db.Decimal(15, 2)
  grandTotal Decimal @db.Decimal(15, 2)
  tpsAsal    Decimal @default(0) @db.Decimal(15, 2)
  totalAkhir Decimal @db.Decimal(15, 2)

  detailSnapshot Json

  status           StatusInvoice    @default(TERBIT)
  statusPembayaran StatusPembayaran @default(BELUM_BAYAR)
  catatan          String?

  createdById String
  createdBy   User     @relation("InvoiceCreatedBy", fields: [createdById], references: [id])
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  deletedAt   DateTime?
  deletedById String?
  deletedBy   User?    @relation("InvoiceDeletedBy", fields: [deletedById], references: [id])
  alasanHapus String?

  paymentId  String?
  paymentUrl String?
  paidAt     DateTime?

  // KRITIS-VERIF-07: Unique partial index di-enforce via migration
  // 20260518000002_unique_nomor_faktur_pajak. Tidak pakai @unique langsung
  // karena perlu partial (WHERE NOT NULL) — banyak invoice belum ada nomor.
  nomorFakturPajak String?  // REG-01: format xxx.xxx-YY.XXXXXXXX (DJP)

  baris InvoiceBaris[]

  @@index([nomorKW])
  @@index([tahun, sequence])
  @@index([tahun, bulan])         // ← BARU: laporan bulanan
  @@index([tanggalInvoice])
  @@index([deletedAt])
  @@index([status])
  @@index([statusPembayaran])     // ← BARU: filter dashboard "belum bayar"
  @@index([klienId])              // ← BARU: lookup per klien
  @@index([btdDokumenId])         // ← BARU: lookup invoice per dokumen
  @@index([bdnDokumenId])         // ← BARU
  @@index([gudangDokumenId])      // ← BARU
  @@index([konsolidasiDokumenId]) // ← konsolidasi
  @@map("invoices")
}

// ─── Invoice Baris ────────────────────────────────────────────────────────────

model InvoiceBaris {
  id        String   @id @default(cuid())
  invoiceId String
  invoice   Invoice  @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
  urutan    Int
  label     String
  qty20     Int?
  qty40     Int?
  hari      Int?
  cbm       Decimal? @db.Decimal(10, 3)
  tarif     Decimal  @db.Decimal(15, 2)
  jumlah    Decimal  @db.Decimal(15, 2)

  @@index([invoiceId])
  @@map("invoice_baris")
}

// ─── Nomor KW Sequence ────────────────────────────────────────────────────────

model NomorKwSequence {
  tahun    Int @id
  terakhir Int @default(0)

  @@map("nomor_kw_sequence")
}

// ─── Nomor EXP Sequence (Konsolidasi Ekspor) ─────────────────────────────────────

model NomorExpSequence {
  tahun    Int @id
  terakhir Int @default(0)

  @@map("nomor_exp_sequence")
}

// ─── Konsolidasi Dokumen ───────────────────────────────────────────────────────────

model KonsolidasiDokumen {
  id               String        @id @default(cuid())
  bookingRefNo     String
  consignee        String
  klienId          String?
  klien            Klien?        @relation(fields: [klienId], references: [id])
  vessel           String?
  voyage           String?
  tglStuffing      DateTime?
  tglBerangkat     DateTime?
  portLoading      String?       @default("Belawan, Indonesia")
  portDischarge    String?
  containerNo      String?
  ukuran           String?
  jenisKonsolidasi String
  stuffingList     Json          @default("[]")
  status           StatusDokumen @default(TERBUKA)
  catatan          String?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  createdBy String?

  // REG-02: PEB (Pemberitahuan Ekspor Barang)
  nomorPEB   String?
  tanggalPEB DateTime?

  invoices Invoice[]

  @@unique([bookingRefNo, consignee])
  @@index([status])
  @@index([consignee])
  @@index([createdAt])
  @@map("konsolidasi_dokumen")
}

// ─── Audit Log ────────────────────────────────────────────────────────────────

model AuditLog {
  id        String   @id @default(cuid())
  userId    String
  user      User     @relation(fields: [userId], references: [id])
  aksi      String
  entitas   String
  entitasId String?
  dataBefore Json?
  dataAfter  Json?
  ipAddress  String?
  userAgent  String?
  createdAt  DateTime @default(now())

  @@index([userId])
  @@index([entitas, entitasId])
  @@index([createdAt])
  @@index([aksi])  // ← BARU: untuk filter audit log per jenis aksi
  @@map("audit_log")
}
