generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}

enum Role {
  ADMIN
  EDITOR
  VIEWER
}

enum InviteStatus {
  PENDING
  ACCEPTED
  REVOKED
}

enum Network {
  LINKEDIN
  TWITTER
  FACEBOOK
  INSTAGRAM
}

enum PostStatus {
  DRAFT
  SCHEDULED
  PUBLISHED
  FAILED
  PENDING_APPROVAL
  REJECTED
}

enum PostSource {
  HUMAN
  HUBSPOT
}

enum ContentTrack {
  ENTERPRISE
  PRODUCT
  DEVELOPER
  THOUGHT_LEADERSHIP
  EVENT
  TI_CULTURAL
}

enum Region {
  APAC
  NA
  EMEA
  LATAM
  GLOBAL
}

enum EngagementType {
  COMMENT
  MENTION
  DM
}

enum EngagementStatus {
  UNREAD
  REPLIED
  IGNORED
}

enum WebhookStatus {
  RECEIVED
  PROCESSED
  FAILED
}

enum NotificationType {
  POST_PUBLISHED
  POST_FAILED
  APPROVAL_NEEDED
  POST_SCHEDULED
  POST_APPROVED
  POST_REJECTED
}

model User {
  id             String             @id @default(cuid())
  email          String             @unique
  name           String?
  image          String?
  role           Role               @default(VIEWER)
  createdAt      DateTime           @default(now())
  updatedAt      DateTime           @updatedAt
  apiKeys        ApiKey[]
  socialAccounts SocialAccount[]
  posts          Post[]
  reviewedPosts  Post[]             @relation("PostReviewer")
  keywords       ListeningKeyword[]
  accounts       Account[]
  sessions       Session[]
  templates      PostTemplate[]
  notifications  Notification[]
  invitesCreated Invite[]           @relation("InviteCreator")
}

model Invite {
  id         String       @id @default(cuid())
  email      String       @unique
  role       Role
  status     InviteStatus @default(PENDING)
  invitedById String
  createdAt  DateTime     @default(now())
  updatedAt  DateTime     @updatedAt
  acceptedAt DateTime?
  invitedBy  User         @relation("InviteCreator", fields: [invitedById], references: [id], onDelete: Cascade)

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

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?
  user              User    @relation(fields: [userId], references: [id], onDelete: Cascade)

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

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

  @@index([userId])
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

model ApiKey {
  id         String    @id @default(cuid())
  userId     String
  keyHash    String
  name       String
  scopes     String    @default("[]")
  lastUsedAt DateTime?
  expiresAt  DateTime?
  createdAt  DateTime  @default(now())
  user       User      @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
}

model SocialAccount {
  id           String              @id @default(cuid())
  userId       String
  network      Network
  accountName  String
  accountId    String
  accessToken  String              @db.Text
  refreshToken String?             @db.Text
  expiresAt    DateTime?
  metadata     String?             @db.Text
  createdAt    DateTime            @default(now())
  user         User                @relation(fields: [userId], references: [id], onDelete: Cascade)
  postAccounts PostSocialAccount[]

  @@index([userId])
}

model Post {
  id                String          @id @default(cuid())
  content           String          @db.Text
  mediaUrls         String          @default("[]")
  networks          String          @default("[]")
  status            PostStatus      @default(DRAFT)
  scheduledAt           DateTime?
  originalScheduledAt   DateTime?
  publishedAt           DateTime?
  tags              String          @default("[]")
  audienceTargeting String?         @db.Text
  source            PostSource      @default(HUMAN)
  sourceRef         String?
  campaignId        String?
  authorId          String
  createdAt         DateTime        @default(now())
  updatedAt         DateTime        @updatedAt
  firstComment      String?         @db.Text
  notes             String?         @db.Text
  track             ContentTrack?
  region            Region?
  publishPriority   String          @default("NORMAL")
  retryCount        Int             @default(0)
  nextRetryAt       DateTime?
  queuePosition     Int?
  reviewerId        String?
  contentVariants   String          @default("{}") @db.VarChar(10000)
  isArticle         Boolean         @default(false)
  reviewComment     String?         @db.Text
  reviewedAt        DateTime?
  author            User            @relation(fields: [authorId], references: [id])
  reviewer          User?           @relation("PostReviewer", fields: [reviewerId], references: [id])
  campaign          Campaign?       @relation(fields: [campaignId], references: [id])
  analytics         PostAnalytics[]
  postAccounts      PostSocialAccount[]

  statusHistory     PostStatusHistory[]

  @@index([authorId])
  @@index([campaignId])
  @@index([status, scheduledAt])
  @@index([reviewerId])
  // Analytics indexes — used by $queryRaw aggregation queries
  @@index([status, publishedAt])
  @@index([track, status, publishedAt])
  @@index([campaignId, publishedAt])
}

model PostStatusHistory {
  id         String     @id @default(cuid())
  postId     String
  fromStatus PostStatus
  toStatus   PostStatus
  changedBy  String
  reason     String?    @db.Text
  createdAt  DateTime   @default(now())
  post       Post       @relation(fields: [postId], references: [id], onDelete: Cascade)

  @@index([postId])
}

model PostSocialAccount {
  id              String        @id @default(cuid())
  postId          String
  socialAccountId String
  externalId      String?
  publishStatus      String        @default("PENDING")
  staggeredPublishAt DateTime?
  post               Post          @relation(fields: [postId], references: [id], onDelete: Cascade)
  socialAccount      SocialAccount @relation(fields: [socialAccountId], references: [id])

  @@index([postId])
  @@index([socialAccountId])
  @@index([staggeredPublishAt])
}

enum CampaignStatus {
  PLANNING
  ACTIVE
  COMPLETED
}

model Campaign {
  id          String          @id @default(cuid())
  name        String
  tags        String          @default("[]")
  description String?         @db.Text
  startDate   DateTime?
  endDate     DateTime?
  status      CampaignStatus  @default(PLANNING)
  region      Region?
  externalRef String?
  createdAt   DateTime        @default(now())
  updatedAt   DateTime        @updatedAt
  posts       Post[]
}

model PostAnalytics {
  id          String   @id @default(cuid())
  postId      String
  network     Network
  impressions Int      @default(0)
  reach       Int      @default(0)
  clicks      Int      @default(0)
  shares      Int      @default(0)
  comments    Int      @default(0)
  reactions   Int      @default(0)
  fetchedAt   DateTime @default(now())
  post        Post     @relation(fields: [postId], references: [id], onDelete: Cascade)

  @@index([postId])
  // Analytics query indexes
  @@index([network, postId])
  @@index([fetchedAt])
}

model EngagementItem {
  id         String           @id @default(cuid())
  network    Network
  type       EngagementType
  content    String           @db.Text
  authorName String
  postId     String?
  externalId String
  status     EngagementStatus @default(UNREAD)
  repliedAt  DateTime?
  createdAt  DateTime         @default(now())
}

model ListeningKeyword {
  id          String   @id @default(cuid())
  keyword     String
  networks    String   @default("[]")
  createdById String
  createdAt   DateTime @default(now())
  createdBy   User     @relation(fields: [createdById], references: [id])

  @@index([createdById])
}

model WebhookLog {
  id          String        @id @default(cuid())
  source      String
  externalId  String?
  payload     String        @db.Text
  status      WebhookStatus @default(RECEIVED)
  error       String?       @db.Text
  processedAt DateTime?
  createdAt   DateTime      @default(now())

  @@index([externalId])
}

model PostTemplate {
  id        String        @id @default(cuid())
  title     String
  content   String        @db.Text
  track     ContentTrack?
  network   Network?
  hashtags  String        @default("[]")
  isShared  Boolean       @default(true)
  createdBy String
  createdAt DateTime      @default(now())
  updatedAt DateTime      @updatedAt
  author    User          @relation(fields: [createdBy], references: [id])

  @@index([createdBy])
  @@index([isShared])
}

model Notification {
  id        String           @id @default(cuid())
  userId    String
  type      NotificationType
  message   String           @db.Text
  postId    String?
  read      Boolean          @default(false)
  createdAt DateTime         @default(now())
  user      User             @relation(fields: [userId], references: [id], onDelete: Cascade)

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

model TrackConfig {
  id                  String       @id @default(cuid())
  track               ContentTrack @unique
  platformWeights     String       @default("{}")
  weeklySlotCap       Int          @default(3)
  requiresApproval    Boolean      @default(true)
  bestWindows         String       @default("[]")
  regionBestWindows   String       @default("{}") @db.Text
  isActive            Boolean      @default(true)
  staggerDelayMinutes     Int          @default(15)
  sourceApprovalPolicy    String       @default("{}")
  conflictWindowMinutes   Int          @default(30)
  dailyQuota              String       @default("{}")
  updatedAt               DateTime     @updatedAt
}

/// Persistent rate limit counters — survives restarts, shared across instances.
model RateLimit {
  key         String   @id
  count       Int      @default(0)
  windowStart BigInt   // Unix timestamp ms when the current window started
  expiresAt   BigInt   // Unix timestamp ms when this window expires

  @@index([expiresAt])
}
