// Prisma schema for ShieldAI
// All models for the multi-service SaaS platform

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

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

// ============================================
// User & Authentication Models
// ============================================

model User {
  id            String    @id @default(uuid())
  email         String    @unique
  emailVerified DateTime?
  name          String?
  image         String?
  role          UserRole  @default(user)
  
  // Relationships
  accounts              Account[]
  sessions              Session[]
  deviceTokens          DeviceToken[]
  familyGroups          FamilyGroupMember[]
  familyGroupOwned      FamilyGroup[] @relation("FamilyGroupOwner")
  subscriptions         Subscription[]
  alerts                Alert[]
  voiceEnrollments      VoiceEnrollment[]
  voiceAnalyses         VoiceAnalysis[]
  spamFeedback          SpamFeedback[]
  spamRules             SpamRule[]
  normalizedAlerts      NormalizedAlert[]
  correlationGroups     CorrelationGroup[]
  securityReports       SecurityReport[]
  analysisJobs          AnalysisJob[]
  
  // Audit
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

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

enum UserRole {
  user
  family_admin
  family_member
  support
}

enum DetectionVerdict {
  NATURAL
  SYNTHETIC
  UNCERTAIN
}

enum AnalysisType {
  SYNTHETIC_DETECTION
  VOICE_MATCH
  BATCH
}

enum AnalysisJobStatus {
  PENDING
  RUNNING
  COMPLETED
  FAILED
}

model Account {
  id                String    @id @default(uuid())
  userId            String
  provider          String
  providerAccountId String
  access_token      String?
  refresh_token     String?
  expires_at        Int?
  token_type        String?
  scope             String?
  
  user              User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt         DateTime  @default(now())
  updatedAt         DateTime  @updatedAt

  @@unique([userId, provider, providerAccountId])
  @@index([userId])
}

model Session {
  id           String   @id @default(uuid())
  userId       String
  sessionToken String   @unique
  expires      DateTime
  
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

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

model DeviceToken {
  id          String   @id @default(uuid())
  userId      String
  deviceType  DeviceType
  token       String   @unique
  platform    Platform
  appName     String?
  appVersion  String?
  osVersion   String?
  model       String?
  isActive    Boolean  @default(true)
  lastUsedAt  DateTime @default(now())
  
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([userId])
  @@index([deviceType])
  @@index([platform])
  @@index([isActive])
}

enum DeviceType {
  mobile
  web
  desktop
}

enum Platform {
  ios
  android
  web
}

// ============================================
// Family & Subscription Models
// ============================================

model FamilyGroup {
  id          String   @id @default(uuid())
  name        String
  ownerId     String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  
  owner       User     @relation("FamilyGroupOwner", fields: [ownerId], references: [id])
  members     FamilyGroupMember[]
  subscriptions Subscription[]
  
  @@index([ownerId])
  @@index([name])
}

model FamilyGroupMember {
  id        String   @id @default(uuid())
  groupId   String
  userId    String
  role      FamilyMemberRole @default(member)
  joinedAt  DateTime @default(now())
  
  group     FamilyGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
  user      User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

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

enum FamilyMemberRole {
  owner
  admin
  member
}

model Subscription {
  id              String         @id @default(uuid())
  userId          String
  familyGroupId   String?
  stripeId        String?        @unique
  tier            SubscriptionTier @default(basic)
  status          SubscriptionStatus @default(active)
  currentPeriodStart DateTime
  currentPeriodEnd DateTime
  cancelAtPeriodEnd Boolean      @default(false)
  
  user            User           @relation(fields: [userId], references: [id], onDelete: Cascade)
  familyGroup     FamilyGroup?   @relation(fields: [familyGroupId], references: [id])
  
  watchlistItems  WatchlistItem[]
  exposures       Exposure[]
  alerts          Alert[]
  propertyWatchlistItems PropertyWatchlistItem[]
  removalRequests RemovalRequest[]
  brokerListings  BrokerListing[]
  
  createdAt       DateTime       @default(now())
  updatedAt       DateTime       @updatedAt

  @@index([userId])
  @@index([familyGroupId])
  @@index([stripeId])
  @@index([tier])
}

enum SubscriptionTier {
  basic
  plus
  premium
}

enum SubscriptionStatus {
  active
  past_due
  canceled
  unpaid
  trialing
}

// ============================================
// DarkWatch Models (Dark Web Monitoring)
// ============================================

model WatchlistItem {
  id            String        @id @default(uuid())
  subscriptionId String
  type          WatchlistType
  value         String
  hash          String        // SHA-256 hash for deduplication
  isActive      Boolean       @default(true)
  
  subscription  Subscription  @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
  exposures     Exposure[]
  
  createdAt     DateTime      @default(now())
  updatedAt     DateTime      @updatedAt

  @@unique([subscriptionId, type, hash])
  @@index([subscriptionId])
  @@index([type])
  @@index([hash])
}

enum WatchlistType {
  email
  phoneNumber
  ssn
  address
  domain
}

model Exposure {
  id              String        @id @default(uuid())
  subscriptionId  String
  watchlistItemId String?
  source          ExposureSource
  dataType        WatchlistType
  identifier      String
  identifierHash  String
  severity        ExposureSeverity @default(info)
  metadata        Json?         // Additional source-specific data
  isFirstTime     Boolean       @default(false)
  
  subscription    Subscription  @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
  watchlistItem   WatchlistItem? @relation(fields: [watchlistItemId], references: [id])
  alerts          Alert[]
  
  detectedAt      DateTime
  createdAt       DateTime      @default(now())
  updatedAt       DateTime      @updatedAt

  @@index([subscriptionId])
  @@index([watchlistItemId])
  @@index([source])
  @@index([severity])
  @@index([detectedAt])
}

enum ExposureSource {
  hibp           // Have I Been Pwned
  securityTrails
  censys
  darkWebForum
  shodan
  honeypot
}

enum ExposureSeverity {
  info
  warning
  critical
}

// ============================================
// Notification & Alert Models
// ============================================

model Alert {
  id              String      @id @default(uuid())
  subscriptionId  String
  userId          String
  exposureId      String?
  type            AlertType
  title           String
  message         String
  severity        AlertSeverity @default(info)
  isRead          Boolean     @default(false)
  readAt          DateTime?
  channel         AlertChannel[] // Array of notification channels
  
  subscription    Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
  user            User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  exposure        Exposure?    @relation(fields: [exposureId], references: [id])
  
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt

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

enum AlertType {
  exposure_detected
  exposure_resolved
  scan_complete
  subscription_changed
  system_warning
}

enum AlertSeverity {
  info
  warning
  critical
}

enum AlertChannel {
  email
  push
  sms
}

// ============================================
// VoicePrint Models (Voice Cloning Detection)
// ============================================

model VoiceEnrollment {
  id            String    @id @default(uuid())
  userId        String
  name          String
  voiceHash     String    // FAISS embedding hash
  audioMetadata Json?     // Sample rate, duration, etc.
  
  user          User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  analyses      VoiceAnalysis[]
  
  isActive      Boolean   @default(true)
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

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

model VoiceAnalysis {
  id              String      @id @default(uuid())
  enrollmentId    String?
  userId          String
  audioHash       String      // Content hash of audio file
  isSynthetic     Boolean
  confidence      Float       // 0.0 to 1.0
  analysisResult  Json        // Full ML analysis results
  audioUrl        String      // S3 storage URL
  
  enrollment      VoiceEnrollment? @relation(fields: [enrollmentId], references: [id])
  user            User        @relation(fields: [userId], references: [id])
  
  createdAt       DateTime    @default(now())

  @@index([userId])
  @@index([enrollmentId])
  @@index([audioHash])
}

model AnalysisJob {
  id              String        @id @default(uuid())
  userId          String
  analysisType    AnalysisType
  audioFilePath   String
  status          AnalysisJobStatus
  errorMessage    String?
  completedAt     DateTime?
  createdAt       DateTime      @default(now())
  
  user            User          @relation(fields: [userId], references: [id])
  result          AnalysisResult?
  
  @@index([userId])
  @@index([status])
  @@index([createdAt])
}

model AnalysisResult {
  id                  String    @id @default(uuid())
  analysisJobId       String    @unique
  syntheticScore      Float
  verdict             DetectionVerdict
  confidence          Float
  processingTimeMs    Int
  matchedEnrollmentId String?
  matchedSimilarity   Float?
  modelVersion        String?
  
  analysisJob         AnalysisJob @relation(fields: [analysisJobId], references: [id])
  
  createdAt           DateTime  @default(now())

  @@index([analysisJobId])
  @@index([syntheticScore])
  @@index([verdict])
}

// ============================================
// SpamShield Models (Spam Detection)
// ============================================

model SpamFeedback {
  id            String         @id @default(uuid())
  userId        String
  phoneNumber   String
  phoneNumberHash String       // SHA-256 hash
  isSpam        Boolean
  confidence    Float?         // ML model confidence
  feedbackType  FeedbackType
  metadata      Json?          // Call duration, time, etc.
  
  user          User           @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt     DateTime       @default(now())
  updatedAt     DateTime       @updatedAt

  @@index([userId])
  @@index([phoneNumberHash])
  @@index([isSpam])
}

enum FeedbackType {
  initial_detection
  user_confirmation
  user_rejection
  auto_learned
}

model SpamRule {
  id            String    @id @default(uuid())
  userId        String?
  isGlobal      Boolean   @default(false)
  ruleType      RuleType
  pattern       String
  action        RuleAction
  priority      Int       @default(0)
  isActive      Boolean   @default(true)
  
  user          User?     @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

  @@index([userId])
  @@index([isGlobal])
  @@index([ruleType])
}

enum RuleType {
  phoneNumber
  areaCode
  prefix
  pattern
  reputation
}

enum RuleAction {
  block
  flag
  allow
  challenge
}

// ============================================
// Audit & Analytics Models
// ============================================

model AuditLog {
  id        String   @id @default(uuid())
  userId    String?
  action    String
  resource  String
  resourceId String?
  changes   Json?    // Before/after values
  metadata  Json?
  ipAddress String?
  userAgent String?
  
  createdAt DateTime @default(now())

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

model KPISnapshot {
  id          String   @id @default(uuid())
  date        DateTime @unique
  metricName  String
  metricValue Float
  metadata    Json?

  createdAt   DateTime @default(now())

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

// ============================================
// Cross-Service Alert Correlation Models
// ============================================

enum AlertSource {
  DARKWATCH
  SPAMSHIELD
  VOICEPRINT
  CALL_ANALYSIS
  HOME_TITLE
  INFO_BROKER
}

enum AlertCategory {
  BREACH_EXPOSURE
  SPAM_CALL
  SPAM_SMS
  SYNTHETIC_VOICE
  VOICE_MISMATCH
  CALL_ANOMALY
  CALL_QUALITY
  CALL_EVENT
  HOME_TITLE
  INFO_BROKER_LISTING
  INFO_BROKER_REMOVAL
}

enum NormalizedAlertSeverity {
  LOW
  INFO
  MEDIUM
  WARNING
  HIGH
  CRITICAL
}

enum CorrelationStatus {
  ACTIVE
  RESOLVED
  FALSE_POSITIVE
}

model NormalizedAlert {
  id              String            @id @default(uuid())
  source          AlertSource
  category        AlertCategory
  severity        NormalizedAlertSeverity
  userId          String
  title           String
  description     String
  entities        Json
  sourceAlertId   String
  groupId         String?
  payload         Json?
  createdAt       DateTime
  updatedAt       DateTime          @default(now()) @updatedAt

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

  @@unique([sourceAlertId])
  @@index([userId])
  @@index([groupId])
  @@index([source])
  @@index([severity])
  @@index([createdAt])
  @@index([userId, createdAt])
}

model CorrelationGroup {
  id              String              @id @default(uuid())
  userId          String
  entities        Json
  highestSeverity NormalizedAlertSeverity
  status          CorrelationStatus   @default(ACTIVE)
  alertCount      Int                 @default(0)
  summary         String?
  resolvedAt      DateTime?
  createdAt       DateTime            @default(now())
  updatedAt       DateTime            @default(now()) @updatedAt

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

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

// ============================================
// Report Generation Models
// ============================================

enum ReportType {
  MONTHLY_PLUS
  ANNUAL_PREMIUM
  WEEKLY_DIGEST
}

enum ReportStatus {
  PENDING
  GENERATING
  COMPLETED
  FAILED
  DELIVERED
}

model SecurityReport {
  id              String           @id @default(uuid())
  userId          String
  subscriptionId  String
  reportType      ReportType
  status          ReportStatus     @default(PENDING)
  periodStart     DateTime
  periodEnd       DateTime
  title           String
  summary         String?
  htmlContent     String?
  pdfUrl          String?
  dataPayload     Json?
  error           String?
  scheduledFor    DateTime?
  deliveredAt     DateTime?

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

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

  @@index([userId])
  @@index([subscriptionId])
  @@index([reportType])
  @@index([status])
  @@index([periodStart, periodEnd])
  @@index([createdAt])
}

// ============================================
// Waitlist & Marketing Models
// ============================================

model WaitlistEntry {
  id            String          @id @default(uuid())
  email         String
  name          String?
  source        String?         // landing_page, blog, referral, social, paid_search
  tier          SubscriptionTier? // interest level
  utmSource     String?
  utmMedium     String?
  utmCampaign   String?
  metadata      Json?           // Browser, device, location, etc.

  // Conversion tracking
  convertedAt   DateTime?
  convertedToUserId String?
  convertedToSubscriptionId String?

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

  @@index([email])
  @@index([source])
  @@index([createdAt])
}

model BlogPost {
  id            String   @id @default(uuid())
  slug          String   @unique
  title         String
  excerpt       String?
  content       String
  authorName    String?
  coverImageUrl String?
  tags          String[]  // Array of tag strings
  published     Boolean  @default(false)
  publishedAt   DateTime?
  viewCount     Int      @default(0)

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

  @@index([slug])
  @@index([published, publishedAt])
  @@index([tags])
}

// ============================================
// Home Title Service Models
// ============================================

enum PropertyChangeType {
  tax_change
  deed_change
  ownership_transfer
  lien_filing
  metadata_change
}

enum PropertyChangeSeverity {
  info
  warning
  critical
}

model PropertyWatchlistItem {
  id              String       @id @default(uuid())
  subscriptionId  String
  address         String
  parcelId        String?
  ownerName       String?
  streetAddress   String
  city            String?      @default("")
  state           String?      @default("")
  zipCode         String?      @default("")
  latitude        Float?
  longitude       Float?
  isActive        Boolean      @default(true)

  subscription    Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
  snapshots       PropertySnapshot[]
  changes         PropertyChange[]

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

  @@unique([subscriptionId, parcelId])
  @@index([subscriptionId])
  @@index([parcelId])
  @@index([address])
}

model PropertySnapshot {
  id              String   @id @default(uuid())
  propertyWatchlistItemId String
  subscriptionId  String
  capturedAt      DateTime
  ownerName       String
  address         Json     // { streetNumber, streetName, streetType, unit, city, state, zip, latitude?, longitude? }
  deedDate        String?
  taxId           String?
  propertyType    String   @default("residential")
  taxAmount       Float?
  lienCount       Int      @default(0)

  propertyWatchlistItem PropertyWatchlistItem @relation(fields: [propertyWatchlistItemId], references: [id], onDelete: Cascade)
  changes               PropertyChange[]     @relation("SnapshotChanges")

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

  @@index([propertyWatchlistItemId])
  @@index([subscriptionId])
  @@index([capturedAt])
}

model PropertyChange {
  id              String             @id @default(uuid())
  propertyWatchlistItemId String
  snapshotId      String?
  changeType      PropertyChangeType
  severity        PropertyChangeSeverity @default(info)
  details         Json?
  detectedAt      DateTime           @default(now())

  propertyWatchlistItem PropertyWatchlistItem @relation(fields: [propertyWatchlistItemId], references: [id], onDelete: Cascade)
  snapshot          PropertySnapshot?      @relation("SnapshotChanges", fields: [snapshotId], references: [id])

  @@index([propertyWatchlistItemId])
  @@index([snapshotId])
  @@index([changeType])
}

// ============================================
// Info Broker Removal Models
// ============================================

enum BrokerCategory {
  PEOPLE_SEARCH
  BACKGROUND_CHECK
  PUBLIC_RECORDS
  REVERSE_LOOKUP
  SOCIAL_MEDIA
}

enum RemovalMethod {
  AUTOMATED
  MANUAL_FORM
  EMAIL
  PHONE
  MAIL
  NONE
}

enum RemovalStatus {
  PENDING
  SUBMITTED
  IN_PROGRESS
  COMPLETED
  FAILED
  REJECTED
  CANCELLED
}

model InfoBroker {
  id              String           @id @default(uuid())
  name            String
  domain          String           @unique
  category        BrokerCategory
  removalMethod   RemovalMethod
  removalUrl      String?
  requiresAccount Boolean          @default(false)
  requiresVerification Boolean     @default(false)
  estimatedDays   Int              @default(14)
  isActive        Boolean          @default(true)

  removalRequests RemovalRequest[]

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

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

model RemovalRequest {
  id              String            @id @default(uuid())
  subscriptionId  String
  brokerId        String
  status          RemovalStatus     @default(PENDING)
  personalInfo    Json              // { fullName, email?, phone?, address?, dob? }
  method          RemovalMethod
  attempts        Int               @default(0)
  nextRetryAt     DateTime?
  submittedAt     DateTime?
  completedAt     DateTime?
  error           String?
  notes           String?
  metadata        Json?             // Broker response data, tracking info

  broker          InfoBroker        @relation(fields: [brokerId], references: [id])
  subscription    Subscription      @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
  brokerListings  BrokerListing[]

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

  @@index([subscriptionId])
  @@index([brokerId])
  @@index([status])
  @@index([submittedAt])
  @@index([subscriptionId, status])
}

model BrokerListing {
  id              String            @id @default(uuid())
  subscriptionId  String
  brokerId        String
  removalRequestId String?
  url             String
  dataFound       Json              // Fields found on the listing
  screenshotUrl   String?
  isRemoved       Boolean           @default(false)
  removedAt       DateTime?

  removalRequest  RemovalRequest?   @relation(fields: [removalRequestId], references: [id])
  subscription    Subscription      @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)

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

  @@index([subscriptionId])
  @@index([brokerId])
  @@index([removalRequestId])
  @@index([isRemoved])
  @@index([subscriptionId, isRemoved])
}
