// ─────────────────────────────────────────────────────────────────────────────
// Prisma Schema — NewWhats SaaS Omnichannel
// ─────────────────────────────────────────────────────────────────────────────

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "debian-openssl-3.0.x", "debian-openssl-1.1.x"]
}

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

// ─── PLANOS ──────────────────────────────────────────────────────────────────

model Plan {
  id          String   @id @default(uuid())
  name        String
  maxInstances Int     @default(1)
  maxAgents    Int     @default(5)
  priceMonthly Decimal @default(0) @db.Decimal(10, 2)
  isActive    Boolean  @default(true)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  users User[]
}

// ─── USUÁRIOS (ADMIN + TENANTS) ───────────────────────────────────────────────

model User {
  id           String   @id @default(uuid())
  name         String
  email        String   @unique
  passwordHash String
  role         UserRole @default(USER)
  isActive     Boolean  @default(true)
  planId       String?
  trialEndsAt  DateTime?
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  plan      Plan?      @relation(fields: [planId], references: [id])
  instances Instance[]
  sectors   Sector[]
  teams     Team[]
  apiKeys   ApiKey[]
  aiCredentials AICredential[]
  aiBots        AIBot[]
  broadcasts        Broadcast[]
  pluginPairs       PluginPair[]
  extWebhooks       ExtWebhook[]
  messageTemplates  MessageTemplate[]
  scheduledMessages ScheduledMessage[]

  @@map("users")
}


enum UserRole {
  ADMIN
  USER
}

// ─── API KEYS ─────────────────────────────────────────────────────────────────

model ApiKey {
  id        String   @id @default(uuid())
  tenantId  String
  key       String   @unique @default(uuid())
  name      String
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())
  expiresAt DateTime?

  tenant User @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  @@map("api_keys")
}

// ─── INSTÂNCIAS WHATSAPP ──────────────────────────────────────────────────────

model Instance {
  id          String         @id @default(uuid())
  tenantId    String
  name        String
  phone       String?
  avatar      String?
  status      InstanceStatus @default(DISCONNECTED)
  engine      String         @default("infinite")
  sessionPath String?
  webhookUrl  String?
  createdAt   DateTime       @default(now())
  updatedAt   DateTime       @updatedAt

  tenant     User        @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  contacts   Contact[]
  chats      Chat[]
  messages   Message[]
  broadcasts Broadcast[]

  @@unique([tenantId, name])
  @@map("instances")
}

enum InstanceStatus {
  DISCONNECTED
  CONNECTING
  QR_PENDING
  CONNECTED
  BANNED
}

// ─── SETORES ─────────────────────────────────────────────────────────────────

model Sector {
  id        String   @id @default(uuid())
  tenantId  String
  name      String
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  tenant    User       @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  teams     Team[]
  protocols Protocol[]

  @@unique([tenantId, name])
  @@map("sectors")
}

// ─── EQUIPES ─────────────────────────────────────────────────────────────────

model Team {
  id        String   @id @default(uuid())
  tenantId  String
  sectorId  String
  name      String
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  tenant    User       @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  sector    Sector     @relation(fields: [sectorId], references: [id], onDelete: Cascade)
  protocols Protocol[]

  @@unique([tenantId, sectorId, name])
  @@map("teams")
}

// ─── CONTATOS ─────────────────────────────────────────────────────────────────

model Contact {
  id             String   @id @default(uuid())
  tenantId       String
  instanceId     String
  jid            String
  lidJid         String?
  // Prioridade: name (agenda) > verifiedName > notify (pushname)
  name           String?
  verifiedName   String?
  notify         String?
  phone          String?
  avatarUrl      String?
  scoreReputacao Int      @default(100)
  flagRestricao  Boolean  @default(false)
  isBlocked      Boolean  @default(false)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  instance  Instance   @relation(fields: [instanceId], references: [id], onDelete: Cascade)
  chats     Chat[]
  protocols Protocol[]

  @@unique([tenantId, instanceId, jid])
  @@index([tenantId, instanceId, lidJid])
  @@map("contacts")
}

// ─── CHATS ────────────────────────────────────────────────────────────────────

model Chat {
  id            String   @id @default(uuid())
  tenantId      String
  instanceId    String
  contactId     String?
  jid           String
  name          String?  // Subject para grupos (@g.us); null para individuais
  unreadCount   Int      @default(0)
  lastMessageAt DateTime?
  isPinned      Boolean  @default(false)
  isArchived    Boolean  @default(false)
  // IA Chatbot
  botPaused     Boolean  @default(false)   // human takeover — pausa o bot neste chat
  botSummary    String?                    // Cérebro: resumo de 2 frases da conversa
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  instance  Instance  @relation(fields: [instanceId], references: [id], onDelete: Cascade)
  contact   Contact?  @relation(fields: [contactId], references: [id])
  messages  Message[]
  protocols Protocol[]

  @@unique([tenantId, instanceId, jid])
  // Índice composto para a query principal da inbox:
  //   WHERE tenantId + instanceId + isArchived  (filtro)
  //   ORDER BY isPinned DESC, lastMessageAt DESC (ordenação)
  @@index([tenantId, instanceId, isArchived, isPinned(sort: Desc), lastMessageAt(sort: Desc)])
  @@map("chats")
}

// ─── MENSAGENS ────────────────────────────────────────────────────────────────

model Message {
  id          String        @id @default(uuid())
  tenantId    String
  instanceId  String
  chatId      String
  remoteJid   String
  messageId   String
  fromMe      Boolean       @default(false)
  type        MessageType   @default(TEXT)
  body        String?
  caption     String?
  mediaUrl    String?
  mediaPath   String?
  mimeType    String?
  fileName    String?
  duration    Int?
  pushName    String?       // Nome do remetente no momento do envio (grupos: quem enviou)
  senderJid   String?       // JID do remetente real (grupos: key.participant)
  replyToId   String?       // ID da mensagem citada (reply)
  richPayload Json?         // Payload rico original (buttons/list/carousel/poll)
  status      MessageStatus @default(PENDING)
  timestamp   DateTime
  createdAt   DateTime      @default(now())

  instance Instance  @relation(fields: [instanceId], references: [id], onDelete: Cascade)
  chat     Chat      @relation(fields: [chatId], references: [id], onDelete: Cascade)
  replyTo  Message?  @relation("MessageReply", fields: [replyToId], references: [id])
  replies  Message[] @relation("MessageReply")

  @@unique([instanceId, messageId])
  // Índice para "última mensagem por chat" — usado no include da inbox
  //   ORDER BY timestamp DESC LIMIT 1  (por chatId)
  @@index([chatId, timestamp(sort: Desc)])
  // Índice para reconcile-names: DISTINCT ON remoteJid ORDER BY timestamp DESC
  //   WHERE instanceId = ? AND fromMe = false AND pushName IS NOT NULL
  @@index([instanceId, fromMe, remoteJid, timestamp(sort: Desc)])
  // Índice para obter a última mensagem da instância — usado na verificação de gap de sincronização
  @@index([instanceId, timestamp(sort: Desc)])
  @@map("messages")
}

enum MessageType {
  TEXT
  IMAGE
  VIDEO
  AUDIO
  DOCUMENT
  STICKER
  LOCATION
  CONTACT
  REACTION
  POLL
  BUTTONS
  LIST
  CAROUSEL
  INTERACTIVE
  UNSUPPORTED
}

enum MessageStatus {
  PENDING
  SENT
  DELIVERED
  READ
  FAILED
}

// ─── PROTOCOLOS DE ATENDIMENTO ────────────────────────────────────────────────

model Protocol {
  id         String         @id @default(uuid())
  tenantId   String
  number     String         @unique // Número sequencial rastreável: #0001-2024
  chatId     String
  contactId  String
  sectorId   String?
  teamId     String?
  agentId    String?
  status     ProtocolStatus @default(OPEN)
  summary    String?        // Resumo de 2 frases gerado pelo Temporal
  deadline   DateTime?
  resolvedAt DateTime?
  createdAt  DateTime       @default(now())
  updatedAt  DateTime       @updatedAt

  chat    Chat    @relation(fields: [chatId], references: [id])
  contact Contact @relation(fields: [contactId], references: [id])
  sector  Sector? @relation(fields: [sectorId], references: [id])
  team    Team?   @relation(fields: [teamId], references: [id])

  // Índice para filtro de protocolos abertos por chat (usado no include da inbox)
  //   WHERE chatId = ? AND status IN ('OPEN', 'IN_PROGRESS', ...) ORDER BY createdAt DESC
  @@index([chatId, status, createdAt(sort: Desc)])
  @@map("protocols")
}

enum ProtocolStatus {
  OPEN
  IN_PROGRESS
  WAITING_CLIENT
  WAITING_AGENT
  RESOLVED
  CANCELLED
}

// ─── IA MULTI-AGENTE ──────────────────────────────────────────────────────────

model AICredential {
  id         String      @id @default(uuid())
  tenantId   String
  instanceId String
  name       String
  provider   LLMProvider @default(GEMINI)
  apiKey     String
  createdAt  DateTime    @default(now())

  tenant User    @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  bots   AIBot[]

  @@unique([tenantId, instanceId, name])
  @@map("ai_credentials")
}

model AIBot {
  id           String      @id @default(uuid())
  tenantId     String
  instanceId   String
  credentialId String
  name         String
  systemPrompt String      @db.Text
  model        String      @default("gemini-1.5-flash")
  enabled      Boolean     @default(false)
  triggerMode  TriggerMode @default(ALL)
  keywords     String[]
  createdAt    DateTime    @default(now())
  updatedAt    DateTime    @updatedAt

  tenant     User         @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  credential AICredential @relation(fields: [credentialId], references: [id])

  @@unique([tenantId, instanceId])
  @@map("ai_bots")
}

enum LLMProvider {
  GEMINI
  OPENAI
}

enum TriggerMode {
  ALL
  KEYWORD
}

// ─── BROADCAST (DISPARO EM MASSA) ─────────────────────────────────────────────

model Broadcast {
  id          String   @id @default(uuid())
  tenantId    String
  instanceId  String
  message     String   @db.Text
  totalCount  Int      @default(0)
  sentCount   Int      @default(0)
  failedCount Int      @default(0)
  status      String   @default("RUNNING") // RUNNING | DONE | FAILED
  createdAt   DateTime @default(now())
  finishedAt  DateTime?

  tenant     User                @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  instance   Instance            @relation(fields: [instanceId], references: [id], onDelete: Cascade)
  recipients BroadcastRecipient[]

  @@map("broadcasts")
}

// ─── PLUGIN PAIRS ─────────────────────────────────────────────────────────────
// Registra sistemas externos pareados com uma conta NewWhats.
// Cada par tem uma integration_key exclusiva que autentica chamadas /nw/*.

model PluginPair {
  id             String    @id @default(uuid())
  userId         String
  clientSystem   String    // identificador técnico ex: "alemao-conveniencias"
  clientName     String    // nome amigável ex: "Alemão Conveniências"
  clientUrl      String?   // URL base do sistema cliente
  integrationKey String    @unique
  lastSeenAt     DateTime?
  revokedAt      DateTime?
  createdAt      DateTime  @default(now())

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

  @@map("plugin_pairs")
}

// ─── EXT WEBHOOKS ─────────────────────────────────────────────────────────────
// Endpoints externos registrados por tenant para receber push de eventos.

model ExtWebhook {
  id        String   @id @default(uuid())
  tenantId  String
  url       String
  events    String[]
  secret    String
  active    Boolean  @default(true)
  createdAt DateTime @default(now())

  tenant User @relation(fields: [tenantId], references: [id], onDelete: Cascade)

  @@map("ext_webhooks")
}

model BroadcastRecipient {
  id          String   @id @default(uuid())
  broadcastId String
  jid         String
  status      String   @default("PENDING") // PENDING | SENT | FAILED
  createdAt   DateTime @default(now())

  broadcast Broadcast @relation(fields: [broadcastId], references: [id], onDelete: Cascade)

  @@map("broadcast_recipients")
}

// ─── TEMPLATES DE MENSAGEM ────────────────────────────────────────────────────

model MessageTemplate {
  id          String       @id @default(uuid())
  tenantId    String
  name        String
  description String?
  type        TemplateType @default(TEXT)
  payload     Json
  tags        String[]
  usageCount  Int          @default(0)
  createdAt   DateTime     @default(now())
  updatedAt   DateTime     @updatedAt

  tenant    User               @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  schedules ScheduledMessage[]

  @@map("message_templates")
}

enum TemplateType {
  TEXT
  BUTTONS
  INTERACTIVE
  LIST
  POLL
  CAROUSEL
}

// ─── AGENDAMENTOS DE MENSAGEM ─────────────────────────────────────────────────

model ScheduledMessage {
  id            String         @id @default(uuid())
  tenantId      String
  instanceId    String
  name          String
  templateId    String?
  payload       Json
  recipientMode RecipientMode  @default(MANUAL)
  recipients    Json
  scheduleType  ScheduleType   @default(ONCE)
  cronExpr      String?
  scheduledAt   DateTime?
  eventType     EventType?
  timezone      String         @default("America/Sao_Paulo")
  status        ScheduleStatus @default(ACTIVE)
  lastRunAt     DateTime?
  nextRunAt     DateTime?
  runCount      Int            @default(0)
  createdAt     DateTime       @default(now())
  updatedAt     DateTime       @updatedAt

  tenant   User                  @relation(fields: [tenantId], references: [id], onDelete: Cascade)
  template MessageTemplate?      @relation(fields: [templateId], references: [id])
  logs     ScheduledMessageLog[]

  @@map("scheduled_messages")
}

model ScheduledMessageLog {
  id          String   @id @default(uuid())
  scheduleId  String
  status      String
  sentCount   Int      @default(0)
  failedCount Int      @default(0)
  error       String?
  runAt       DateTime @default(now())

  schedule ScheduledMessage @relation(fields: [scheduleId], references: [id], onDelete: Cascade)

  @@map("scheduled_message_logs")
}

enum RecipientMode {
  MANUAL
  ALL_CONTACTS
  TAG_FILTER
}

enum ScheduleType {
  ONCE
  RECURRING
  EVENT
}

enum EventType {
  BIRTHDAY
  ANNIVERSARY
  SIGNUP_DAYS
}

enum ScheduleStatus {
  ACTIVE
  PAUSED
  DONE
  CANCELLED
}
// ─── FIGURINHAS (STICKERS) ────────────────────────────────────────────────────
// Armazenamento persistente de stickers usando fileSha256 do protocolo Baileys
// como chave de conteúdo. Garante deduplicação mesmo após reinstalação do WA.

model Sticker {
  id          String   @id @default(uuid())
  tenantId    String
  instanceId  String
  sha256      String   // fileSha256 hex — identidade permanente do conteúdo
  wasabiPath  String   // stickers/{tenantId}/{sha256}.webp
  isAnimated  Boolean  @default(false)
  isFavorite  Boolean  @default(false)
  useCount    Int      @default(1)
  lastSeenAt  DateTime @default(now())
  createdAt   DateTime @default(now())

  @@unique([tenantId, sha256])
  @@index([tenantId, instanceId, isFavorite, lastSeenAt(sort: Desc)])
  @@map("stickers")
}

// Webhook allowed host fix
// Webhook allowed host fix
// Webhook query string fix
