// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

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

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

model User {
  id       String  @id @default(cuid())
  slack_id String
  email    String?
  pfpUrl   String

  hackClubVerificationResult    String?
  hackClubVerificationCheckedAt DateTime?
  bypassVerification            Boolean @default(false)

  hasOnboarded Boolean @default(false)
  isAdmin      Boolean @default(false)

  personalChannel   Channel? @relation("PersonalChannel", fields: [personalChannelId], references: [id])
  personalChannelId String?  @unique

  ownedChannels   Channel[]    @relation("ChannelOwner")
  managedChannels Channel[]    @relation("ChannelManagers")
  chatModeratedChannels Channel[] @relation("ChannelChatModerators")
  sessions        Session[]
  streams         StreamInfo[]
  followers       Follow[]     @relation("UserFollows")
  botAccounts     BotAccount[]
  ban             UserBan?
  chatBans        ChatUserBan[]         @relation("ChatBannedUser")
  issuedChatBans  ChatUserBan[]         @relation("ChatBannedBy")
  chatModActions  ChatModerationEvent[] @relation("ChatModerationActor")
  chatModTargets  ChatModerationEvent[] @relation("ChatModerationTarget")
  adminAuditLogs  AdminAuditLog[]       @relation("AdminAuditActor")
  chatReportsMade ChatUserReport[]      @relation("ChatReportReporter")
  chatReportsSeen ChatUserReport[]      @relation("ChatReportTarget")
  chatReportsHandled ChatUserReport[]    @relation("ChatReportHandler")

  @@index([personalChannelId])
}

model Channel {
  id          String @id @default(cuid())
  name        String @unique
  description String @default("A hctv channel")
  pfpUrl      String
  notifChannels String[] @default([])

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

  personalFor User? @relation("PersonalChannel")

  owner             User         @relation("ChannelOwner", fields: [ownerId], references: [id])
  ownerId           String
  managers          User[]       @relation("ChannelManagers")
  chatModerators    User[]       @relation("ChannelChatModerators")
  chatModeratorBots BotAccount[] @relation("ChannelChatBotModerators")
  streamInfo        StreamInfo[]
  followers         Follow[]     @relation("ChannelFollowers")
  streamKey         StreamKey?
  obsChatGrantToken String       @unique @default(cuid())
  is247             Boolean      @default(false)
  restriction       ChannelRestriction?
  chatSettings      ChatModerationSettings?
  chatBans          ChatUserBan[]
  chatModEvents     ChatModerationEvent[]
  chatReports       ChatUserReport[]

  @@index([ownerId])
}

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

model StreamInfo {
  id        String   @id @default(cuid())
  username  String   @unique
  title     String
  thumbnail String
  viewers   Int
  category  String
  startedAt DateTime
  isLive    Boolean
  streamRegion String @default("hq")

  channelId String
  channel   Channel @relation(fields: [channelId], references: [id], onDelete: Cascade)

  ownedBy User   @relation(fields: [userId], references: [id])
  userId  String

  enableNotifications Boolean @default(true)

  @@index([username])
}

model Follow {
  id        String   @id @default(cuid())
  createdAt DateTime @default(now())

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

  channel   Channel @relation("ChannelFollowers", fields: [channelId], references: [id], onDelete: Cascade)
  channelId String

  notifyStream Boolean @default(false)

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

model StreamKey {
  id  String @id @default(cuid())
  key String @unique

  channelId String  @unique
  channel   Channel @relation(fields: [channelId], references: [id], onDelete: Cascade)
}

model BotAccount {
  id          String      @id @default(cuid())
  displayName String
  slug        String      @unique
  description String      @default("A hctv bot account")
  pfpUrl      String
  owner       User        @relation(fields: [ownerId], references: [id])
  ownerId     String
  moderatingChannels Channel[] @relation("ChannelChatBotModerators")
  apiKeys     BotApiKey[]

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

  @@index([ownerId])
  @@index([slug])
}

model BotApiKey {
  id           String     @id @default(cuid())
  name         String
  key          String     @unique
  botAccount   BotAccount @relation(fields: [botAccountId], references: [id], onDelete: Cascade)
  botAccountId String
  createdAt    DateTime   @default(now())

  @@index([botAccountId])
}

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

  @@index([userId])
}

model ChannelRestriction {
  id           String    @id @default(cuid())
  channel      Channel   @relation(fields: [channelId], references: [id], onDelete: Cascade)
  channelId    String    @unique
  reason       String
  restrictedBy String
  createdAt    DateTime  @default(now())
  expiresAt    DateTime?

  @@index([channelId])
}

model ChatModerationSettings {
  id                     String   @id @default(cuid())
  channel                Channel  @relation(fields: [channelId], references: [id], onDelete: Cascade)
  channelId              String   @unique
  blockedTerms           String[] @default([])
  slowModeSeconds        Int      @default(0)
  maxMessageLength       Int      @default(400)
  rateLimitCount         Int      @default(8)
  rateLimitWindowSeconds Int      @default(10)
  createdAt              DateTime @default(now())
  updatedAt              DateTime @updatedAt

  @@index([channelId])
}

model ChatUserBan {
  id         String   @id @default(cuid())
  channel    Channel  @relation(fields: [channelId], references: [id], onDelete: Cascade)
  channelId  String
  user       User     @relation("ChatBannedUser", fields: [userId], references: [id], onDelete: Cascade)
  userId     String
  reason     String
  bannedBy   User     @relation("ChatBannedBy", fields: [bannedById], references: [id], onDelete: Cascade)
  bannedById String
  expiresAt  DateTime?
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  @@unique([channelId, userId])
  @@index([channelId, userId])
  @@index([expiresAt])
}

model ChatModerationEvent {
  id           String               @id @default(cuid())
  channel      Channel              @relation(fields: [channelId], references: [id], onDelete: Cascade)
  channelId    String
  action       ChatModerationAction
  moderator    User                 @relation("ChatModerationActor", fields: [moderatorId], references: [id], onDelete: Cascade)
  moderatorId  String
  targetUser   User?                @relation("ChatModerationTarget", fields: [targetUserId], references: [id], onDelete: SetNull)
  targetUserId String?
  reason       String?
  details      Json?
  createdAt    DateTime             @default(now())

  @@index([channelId, createdAt])
  @@index([moderatorId])
  @@index([targetUserId])
}

model AdminAuditLog {
  id            String           @id @default(cuid())
  action        AdminAuditAction
  actor         User             @relation("AdminAuditActor", fields: [actorId], references: [id], onDelete: Cascade)
  actorId       String
  targetUserId  String?
  targetChannel String?
  reason        String?
  details       Json?
  createdAt     DateTime         @default(now())

  @@index([actorId])
  @@index([createdAt])
  @@index([action, createdAt])
}

model ChatUserReport {
  id                  String           @id @default(cuid())
  channel             Channel          @relation(fields: [channelId], references: [id], onDelete: Cascade)
  channelId           String
  reporter            User             @relation("ChatReportReporter", fields: [reporterId], references: [id], onDelete: Cascade)
  reporterId          String
  targetUser          User?            @relation("ChatReportTarget", fields: [targetUserId], references: [id], onDelete: SetNull)
  targetUserId        String?
  targetUsername      String?
  reportedMessage     String?
  reportedMessageId   String?
  reason              String
  status              ChatReportStatus @default(OPEN)
  handledBy           User?            @relation("ChatReportHandler", fields: [handledById], references: [id], onDelete: SetNull)
  handledById         String?
  handledAt           DateTime?
  handlingNote        String?
  lastAction          ChatReportAction?
  createdAt           DateTime         @default(now())
  updatedAt           DateTime         @updatedAt

  @@index([channelId, createdAt])
  @@index([reporterId, createdAt])
  @@index([status, createdAt])
  @@index([handledById, handledAt])
}

enum ChatReportStatus {
  OPEN
  REVIEWED
  DISMISSED
}

enum ChatReportAction {
  REVIEW
  DISMISS
  DELETE_REPORTED_MESSAGE
  TIMEOUT_10M
  TIMEOUT_1H
  BAN_CHAT
  LIFT_CHAT_BAN
  BAN_PLATFORM
  UNBAN_PLATFORM
}

enum AdminAuditAction {
  USER_BANNED
  USER_UNBANNED
  USER_PROMOTED
  USER_DEMOTED
  CHANNEL_RESTRICTED
  CHANNEL_UNRESTRICTED
  REPORT_REVIEWED
  REPORT_DISMISSED
  REPORT_ENFORCEMENT
  BYPASS_VERIFICATION_ENABLED
  BYPASS_VERIFICATION_DISABLED
}

enum ChatModerationAction {
  MESSAGE_BLOCKED
  MESSAGE_DELETED
  USER_TIMEOUT
  USER_BANNED
  USER_UNBANNED
}
