// =============================================================================
// Prisma Schema - Customer Portal BFF
// =============================================================================
// IMPORTANT: When building Docker images, the Prisma client must be regenerated
// from the production directory structure. See prisma/README.md for details.
// =============================================================================

generator client {
  provider      = "prisma-client-js"
  // Only include engines we actually need:
  // - native: for local development
  // - linux-musl-openssl-3.0.x: for Alpine production
  binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}

datasource db {
  provider = "postgresql"
  // Prisma 7+: URL is configured via prisma.config.ts for migrations
  // and via --url flag for studio. Runtime uses the adapter in PrismaClient.
}

model User {
  id                  String     @id @default(uuid())
  email               String     @unique
  passwordHash        String?    @map("password_hash")
  role                UserRole   @default(USER)

  // Authentication state only - profile data comes from WHMCS
  mfaSecret           String?    @map("mfa_secret")
  emailVerified       Boolean    @default(false) @map("email_verified")
  failedLoginAttempts Int        @default(0) @map("failed_login_attempts")
  lockedUntil         DateTime?  @map("locked_until")
  lastLoginAt         DateTime?  @map("last_login_at")

  createdAt           DateTime   @default(now()) @map("created_at")
  updatedAt           DateTime   @updatedAt @map("updated_at")
  auditLogs           AuditLog[]
  idMapping           IdMapping?
  residenceCardSubmission ResidenceCardSubmission?
  notifications       Notification[]

  @@map("users")
}

model IdMapping {
  userId        String   @id @map("user_id")
  whmcsClientId Int      @unique @map("whmcs_client_id")
  sfAccountId   String   @map("sf_account_id")
  createdAt     DateTime @default(now()) @map("created_at")
  updatedAt     DateTime @updatedAt @map("updated_at")
  user          User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("id_mappings")
}

model AuditLog {
  id        String      @id @default(uuid())
  userId    String?     @map("user_id")
  action    AuditAction
  resource  String?
  details   Json?
  ipAddress String?     @map("ip_address")
  userAgent String?     @map("user_agent")
  success   Boolean     @default(true)
  error     String?
  createdAt DateTime    @default(now()) @map("created_at")
  user      User?       @relation(fields: [userId], references: [id])

  @@index([userId, action])
  @@index([action, createdAt])
  @@index([createdAt])
  @@map("audit_logs")
}

enum UserRole {
  USER
  ADMIN
}

enum AuditAction {
  LOGIN_SUCCESS
  LOGIN_FAILED
  LOGIN_OTP_SENT
  LOGIN_OTP_VERIFIED
  LOGIN_OTP_FAILED
  LOGIN_SESSION_INVALIDATED
  LOGOUT
  SIGNUP
  PASSWORD_RESET
  PASSWORD_CHANGE
  ACCOUNT_LOCKED
  ACCOUNT_UNLOCKED
  PROFILE_UPDATE
  MFA_ENABLED
  MFA_DISABLED
  API_ACCESS
  SYSTEM_MAINTENANCE
  // Address reconciliation (Salesforce dual-write)
  ADDRESS_UPDATE
  ADDRESS_UPDATE_PARTIAL
  ADDRESS_RECONCILE_QUEUED
  ADDRESS_RECONCILE_SUCCESS
  ADDRESS_RECONCILE_FAILED
}

enum ResidenceCardStatus {
  PENDING
  VERIFIED
  REJECTED
}

model ResidenceCardSubmission {
  id           String             @id @default(uuid())
  userId       String             @unique @map("user_id")
  status       ResidenceCardStatus @default(PENDING)
  filename     String
  mimeType     String             @map("mime_type")
  sizeBytes    Int                @map("size_bytes")
  content      Bytes              @db.ByteA
  submittedAt  DateTime           @default(now()) @map("submitted_at")
  reviewedAt   DateTime?          @map("reviewed_at")
  reviewerNotes String?           @map("reviewer_notes")
  createdAt    DateTime           @default(now()) @map("created_at")
  updatedAt    DateTime           @updatedAt @map("updated_at")
  user         User               @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("residence_card_submissions")
}

// Per-SIM daily usage snapshot used to build full-month charts
model SimUsageDaily {
  id        Int      @id @default(autoincrement())
  account   String
  date      DateTime @db.Date
  usageMb   Float
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@unique([account, date])
  @@index([account, date])
  @@map("sim_usage_daily")
}

model SimVoiceOptions {
  account                     String   @id
  voiceMailEnabled            Boolean  @default(false) @map("voice_mail_enabled")
  callWaitingEnabled          Boolean  @default(false) @map("call_waiting_enabled")
  internationalRoamingEnabled Boolean  @default(false) @map("international_roaming_enabled")
  networkType                 String   @default("4G") @map("network_type")
  createdAt                   DateTime @default(now()) @map("created_at")
  updatedAt                   DateTime @updatedAt @map("updated_at")

  @@map("sim_voice_options")
}

// Call history from SFTP monthly imports (domestic calls)
model SimCallHistoryDomestic {
  id          String   @id @default(uuid())
  account     String   // Customer phone number (e.g., "08077052946")
  callDate    DateTime @db.Date @map("call_date") // Date the call was made
  callTime    String   @map("call_time") // Start time of the call (HHMMSS)
  calledTo    String   @map("called_to") // Phone number called
  location    String?  // Location info
  durationSec Int      @map("duration_sec") // Duration in seconds (320 = 32.0 sec)
  chargeYen   Int      @map("charge_yen") // Call charge in JPY
  month       String   // YYYY-MM format for filtering
  createdAt   DateTime @default(now()) @map("created_at")

  @@unique([account, callDate, callTime, calledTo])
  @@index([account, month])
  @@index([account, callDate])
  @@map("sim_call_history_domestic")
}

// Call history from SFTP monthly imports (international calls)
model SimCallHistoryInternational {
  id          String   @id @default(uuid())
  account     String   // Customer phone number
  callDate    DateTime @db.Date @map("call_date") // Date the call was made
  startTime   String   @map("start_time") // Start time of the call
  stopTime    String?  @map("stop_time") // Stop time (if available)
  country     String?  // Country/location for international calls
  calledTo    String   @map("called_to") // Phone number called
  durationSec Int      @map("duration_sec") // Duration in seconds
  chargeYen   Int      @map("charge_yen") // Call charge in JPY
  month       String   // YYYY-MM format for filtering
  createdAt   DateTime @default(now()) @map("created_at")

  @@unique([account, callDate, startTime, calledTo])
  @@index([account, month])
  @@index([account, callDate])
  @@map("sim_call_history_international")
}

// SMS history from SFTP monthly imports
model SimSmsHistory {
  id        String   @id @default(uuid())
  account   String   // Customer phone number
  smsDate   DateTime @db.Date @map("sms_date") // Date the SMS was sent
  smsTime   String   @map("sms_time") // Time the SMS was sent
  sentTo    String   @map("sent_to") // Phone number SMS was sent to
  smsType   SmsType  @default(DOMESTIC) @map("sms_type") // SMS or 国際SMS
  month     String   // YYYY-MM format for filtering
  createdAt DateTime @default(now()) @map("created_at")

  @@unique([account, smsDate, smsTime, sentTo])
  @@index([account, month])
  @@index([account, smsDate])
  @@map("sim_sms_history")
}

enum SmsType {
  DOMESTIC     // ＳＭＳ
  INTERNATIONAL // 国際ＳＭＳ
}

// Track which months have been imported
model SimHistoryImport {
  id          String   @id @default(uuid())
  month       String   @unique // YYYY-MM format
  talkFile    String?  @map("talk_file") // Filename imported
  smsFile     String?  @map("sms_file") // Filename imported
  talkRecords Int      @default(0) @map("talk_records") // Records imported
  smsRecords  Int      @default(0) @map("sms_records") // Records imported
  importedAt  DateTime @default(now()) @map("imported_at")
  status      String   @default("completed") // completed, failed, partial

  @@map("sim_history_imports")
}

// =============================================================================
// Notifications - In-app notifications synced with Salesforce email triggers
// =============================================================================

model Notification {
  id          String             @id @default(uuid())
  userId      String             @map("user_id")
  
  // Notification content
  type        NotificationType
  title       String
  message     String?
  
  // Action (optional CTA button)
  actionUrl   String?            @map("action_url")
  actionLabel String?            @map("action_label")
  
  // Source tracking for deduplication
  source      NotificationSource @default(SALESFORCE)
  sourceId    String?            @map("source_id") // SF Account ID, Order ID, etc.
  
  // Status
  read        Boolean            @default(false)
  readAt      DateTime?          @map("read_at")
  dismissed   Boolean            @default(false)
  
  // Timestamps
  createdAt   DateTime           @default(now()) @map("created_at")
  expiresAt   DateTime           @map("expires_at") // 30 days from creation
  
  user        User               @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, read, dismissed])
  @@index([userId, createdAt])
  @@index([expiresAt])
  @@map("notifications")
}

enum NotificationType {
  ELIGIBILITY_ELIGIBLE
  ELIGIBILITY_INELIGIBLE
  VERIFICATION_VERIFIED
  VERIFICATION_REJECTED
  ORDER_APPROVED
  ORDER_ACTIVATED
  ORDER_FAILED
  CANCELLATION_SCHEDULED
  CANCELLATION_COMPLETE
  PAYMENT_METHOD_EXPIRING
  INVOICE_DUE
  SYSTEM_ANNOUNCEMENT
}

enum NotificationSource {
  SALESFORCE
  WHMCS
  PORTAL
  SYSTEM
}
