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

datasource db {
  provider = "postgresql"
}

enum UserStatus {
  ACTIVE
  SUSPENDED
  DELETED
}

enum SessionStatus {
  ACTIVE
  LOCKED
  REVOKED
  EXPIRED
}

enum DeviceType {
  WEB
  IOS
  ANDROID
  DESKTOP
  TV
  SMART_SPEAKER
  OTHER
}

enum OAuthClientType {
  CONFIDENTIAL
  PUBLIC
}

enum AppReleasePlatform {
  ANDROID
  WINDOWS
}

enum PushPlatform {
  WEB
  ANDROID
  IOS
}

model AppRelease {
  id           String             @id @default(uuid())
  platform     AppReleasePlatform
  version      String
  versionCode  Int
  fileName     String
  storageKey   String             @unique
  fileSize     BigInt
  sha256       String
  releaseNotes String?
  isPublished  Boolean            @default(true)
  createdById  String?
  createdAt    DateTime           @default(now())
  updatedAt    DateTime           @updatedAt

  @@unique([platform, version])
  @@unique([platform, versionCode])
  @@index([platform, isPublished, createdAt])
}

model User {
  id              String          @id @default(uuid())
  email           String?         @unique
  phone           String?         @unique
  backupEmail     String?         @unique
  backupPhone     String?         @unique
  passwordHash    String?
  displayName     String
  username        String?         @unique
  avatarUrl       String?
  avatarStorageKey String?
  birthDate       DateTime?
  gender          String?
  isSuperAdmin    Boolean         @default(false)
  isSystemAccount Boolean         @default(false)
  linkedBotId     String?         @unique
  e2ePublicKey    String?
  isVerified      Boolean         @default(false)
  verificationIcon String?
  verifiedAt      DateTime?
  status          UserStatus      @default(ACTIVE)
  createdAt       DateTime        @default(now())
  updatedAt       DateTime        @updatedAt
  deletedAt       DateTime?
  deletionRequestedAt DateTime?
  pinCode         PinCode?
  sessions        Session[]
  devices         Device[]
  signInEvents    SignInEvent[]
  activityLogs    UserActivityLog[]
  authCodes       AuthCode[]
  linkedAccounts  LinkedAccount[]
  userRoles       UserRole[]
  userPermissions UserPermission[]
  profile         UserProfile?
  documents       UserDocument[]
  addresses       Address[]
  oauthConsents   OAuthConsent[]
  oauthAuthCodes  OAuthAuthorizationCode[]
  ownedFamilyGroups FamilyGroup[]
  familyMemberships FamilyMember[]
  sentFamilyInvites FamilyInvite[] @relation("FamilyInviteInviter")
  receivedFamilyInvites FamilyInvite[] @relation("FamilyInviteInvitee")
  notifications Notification[]
  pushDeviceTokens PushDeviceToken[]
  chatRoomMembers ChatRoomMember[]
  chatMessages ChatMessage[]
  chatPollVotes ChatPollVote[]
  totpSecret    UserTotpSecret?
  createdOAuthClients OAuthClient[] @relation("OAuthClientCreator")
  ownedBots         Bot[]          @relation("BotOwner")
  linkedBot           Bot?           @relation("BotSystemUser", fields: [linkedBotId], references: [id], onDelete: SetNull)
}

model UserTotpSecret {
  id        String   @id @default(uuid())
  userId    String   @unique
  secretEnc String
  isEnabled Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model UserProfile {
  id        String   @id @default(uuid())
  userId    String   @unique
  firstName String?
  lastName  String?
  bio       String?
  age       Int?
  gender    String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model PinCode {
  id                  String    @id @default(uuid())
  userId              String    @unique
  hash                String
  isEnabled           Boolean   @default(false)
  deletionRequestedAt DateTime?
  createdAt           DateTime  @default(now())
  updatedAt           DateTime  @updatedAt
  user                User      @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model Session {
  id          String        @id @default(uuid())
  userId      String
  deviceId    String?
  refreshHash String
  pinVerified Boolean       @default(true)
  status      SessionStatus @default(ACTIVE)
  ipAddress   String?
  userAgent   String?
  expiresAt   DateTime
  lastActivityAt DateTime      @default(now())
  createdAt   DateTime      @default(now())
  updatedAt   DateTime      @updatedAt
  user        User          @relation(fields: [userId], references: [id], onDelete: Cascade)
  device      Device?       @relation(fields: [deviceId], references: [id], onDelete: SetNull)

  @@index([userId, status])
}

model Device {
  id           String        @id @default(uuid())
  userId       String
  name         String
  type         DeviceType    @default(OTHER)
  fingerprint  String
  lastIp       String?
  lastSeenAt   DateTime      @default(now())
  trusted      Boolean       @default(false)
  createdAt    DateTime      @default(now())
  user         User          @relation(fields: [userId], references: [id], onDelete: Cascade)
  sessions     Session[]
  signInEvents SignInEvent[]

  @@unique([userId, fingerprint])
}

model SignInEvent {
  id        String   @id @default(uuid())
  userId    String
  deviceId  String?
  ipAddress String?
  userAgent String?
  success   Boolean
  reason    String?
  createdAt DateTime @default(now())
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  device    Device?  @relation(fields: [deviceId], references: [id], onDelete: SetNull)

  @@index([userId, createdAt])
}

model UserActivityLog {
  id         String   @id @default(uuid())
  userId     String
  action     String
  title      String
  detail     String?
  entityType String?
  entityId   String?
  ipAddress  String?
  userAgent  String?
  actorId    String?
  createdAt  DateTime @default(now())
  user       User     @relation(fields: [userId], references: [id], onDelete: Cascade)

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

model LinkedAccount {
  id           String   @id @default(uuid())
  userId       String
  providerName String
  providerId   String
  email        String?
  displayName  String?
  avatarUrl    String?
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([providerName, providerId])
  @@index([userId])
}

model Role {
  id          String           @id @default(uuid())
  slug        String           @unique
  name        String
  description String?
  isSystem    Boolean          @default(false)
  isDefault   Boolean          @default(false)
  createdAt   DateTime         @default(now())
  updatedAt   DateTime         @updatedAt
  users       UserRole[]
  permissions RolePermission[]
}

model Permission {
  id          String           @id @default(uuid())
  slug        String           @unique
  name        String
  description String?
  createdAt   DateTime         @default(now())
  roles       RolePermission[]
  users       UserPermission[]
}

model UserPermission {
  userId       String
  permissionId String
  createdAt    DateTime   @default(now())
  user         User       @relation(fields: [userId], references: [id], onDelete: Cascade)
  permission   Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)

  @@id([userId, permissionId])
}

model UserRole {
  userId    String
  roleId    String
  createdAt DateTime @default(now())
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  role      Role     @relation(fields: [roleId], references: [id], onDelete: Cascade)

  @@id([userId, roleId])
}

model RolePermission {
  roleId       String
  permissionId String
  createdAt    DateTime   @default(now())
  role         Role       @relation(fields: [roleId], references: [id], onDelete: Cascade)
  permission   Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)

  @@id([roleId, permissionId])
}

model OAuthClient {
  id           String           @id @default(uuid())
  name         String
  clientId     String           @unique
  clientSecret String?
  type         OAuthClientType   @default(CONFIDENTIAL)
  redirectUris String[]
  scopes       OAuthClientScope[]
  isActive     Boolean          @default(true)
  createdById  String?
  createdAt    DateTime         @default(now())
  updatedAt    DateTime         @updatedAt
  createdBy    User?            @relation("OAuthClientCreator", fields: [createdById], references: [id], onDelete: SetNull)
  consents     OAuthConsent[]
  authCodes    OAuthAuthorizationCode[]

  @@index([createdById])
}

model OAuthAuthorizationCode {
  id          String      @id @default(uuid())
  code        String      @unique
  userId      String
  clientId    String
  redirectUri String
  scopes      String[]
  nonce       String?
  expiresAt   DateTime
  consumedAt  DateTime?
  createdAt   DateTime    @default(now())
  user        User        @relation(fields: [userId], references: [id], onDelete: Cascade)
  client      OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)

  @@index([userId, clientId])
}

model OAuthScope {
  id          String             @id @default(uuid())
  slug        String             @unique
  name        String
  description String?
  clients     OAuthClientScope[]
  consents    OAuthConsentScope[]
}

model OAuthClientScope {
  clientId String
  scopeId  String
  client   OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
  scope    OAuthScope  @relation(fields: [scopeId], references: [id], onDelete: Cascade)

  @@id([clientId, scopeId])
}

model OAuthConsent {
  id        String              @id @default(uuid())
  userId    String
  clientId  String
  createdAt DateTime            @default(now())
  updatedAt DateTime            @updatedAt
  user      User                @relation(fields: [userId], references: [id], onDelete: Cascade)
  client    OAuthClient         @relation(fields: [clientId], references: [id], onDelete: Cascade)
  scopes    OAuthConsentScope[]

  @@unique([userId, clientId])
}

model OAuthConsentScope {
  consentId String
  scopeId   String
  consent   OAuthConsent @relation(fields: [consentId], references: [id], onDelete: Cascade)
  scope     OAuthScope   @relation(fields: [scopeId], references: [id], onDelete: Cascade)

  @@id([consentId, scopeId])
}

model UserDocument {
  id        String   @id @default(uuid())
  userId    String
  type      String
  number    String
  issuedAt  DateTime?
  expiresAt DateTime?
  metadata  Json?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model AuthCode {
  id        String    @id @default(uuid())
  userId    String?
  channel   String
  target    String
  codeHash  String
  purpose   String
  expiresAt DateTime
  usedAt    DateTime?
  createdAt DateTime  @default(now())
  user      User?     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([target, purpose, expiresAt])
}

model FamilyGroup {
  id               String         @id @default(uuid())
  ownerId          String
  name             String
  avatarStorageKey String?
  hasAvatar        Boolean        @default(false)
  createdAt        DateTime       @default(now())
  updatedAt        DateTime       @updatedAt
  owner            User           @relation(fields: [ownerId], references: [id], onDelete: Cascade)
  members          FamilyMember[]
  invites          FamilyInvite[]
  chatRooms        ChatRoom[]
}

model FamilyInvite {
  id            String      @id @default(uuid())
  groupId       String
  inviterId     String
  inviteeUserId String?
  targetEmail   String?
  targetPhone   String?
  status        String      @default("PENDING")
  token         String      @unique @default(uuid())
  expiresAt     DateTime
  createdAt     DateTime    @default(now())
  updatedAt     DateTime    @updatedAt
  group         FamilyGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
  inviter       User        @relation("FamilyInviteInviter", fields: [inviterId], references: [id], onDelete: Cascade)
  invitee       User?       @relation("FamilyInviteInvitee", fields: [inviteeUserId], references: [id], onDelete: SetNull)

  @@index([inviteeUserId, status])
  @@index([groupId, status])
}

model Notification {
  id        String   @id @default(uuid())
  userId    String
  type      String
  title     String
  message   String
  payload   Json?
  isRead    Boolean  @default(false)
  createdAt DateTime @default(now())
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)

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

model PushDeviceToken {
  id          String       @id @default(uuid())
  userId      String
  token       String       @unique
  platform    PushPlatform @default(WEB)
  deviceLabel String?
  createdAt   DateTime     @default(now())
  updatedAt   DateTime     @updatedAt
  user        User         @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
}

model ChatRoom {
  id               String           @id @default(uuid())
  groupId          String
  type             String
  name             String
  peerUserId       String?
  botUsername      String?
  isE2E            Boolean          @default(false)
  avatarStorageKey String?
  hasAvatar        Boolean          @default(false)
  createdById      String?
  createdAt        DateTime         @default(now())
  updatedAt        DateTime         @updatedAt
  group            FamilyGroup      @relation(fields: [groupId], references: [id], onDelete: Cascade)
  members          ChatRoomMember[]
  messages         ChatMessage[]
  botChats         BotChat[]

  @@index([groupId, type])
  @@index([groupId, type, peerUserId])
}

model ChatRoomMember {
  id                 String   @id @default(uuid())
  roomId             String
  userId             String
  notificationsMuted Boolean   @default(false)
  pinnedAt           DateTime?
  lastReadAt         DateTime?
  lastReadMessageId  String?
  joinedAt           DateTime  @default(now())
  room               ChatRoom @relation(fields: [roomId], references: [id], onDelete: Cascade)
  user               User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([roomId, userId])
  @@index([userId, pinnedAt])
}

model ChatMessage {
  id          String     @id @default(uuid())
  roomId      String
  senderId    String
  type        String
  content     String?
  isEncrypted Boolean    @default(false)
  replyToId   String?
  metadata    Json?
  storageKey  String?
  mimeType    String?
  isPinned    Boolean    @default(false)
  pinnedAt    DateTime?
  pinnedById  String?
  createdAt   DateTime   @default(now())
  editedAt    DateTime?
  deletedAt   DateTime?
  room       ChatRoom   @relation(fields: [roomId], references: [id], onDelete: Cascade)
  sender     User       @relation(fields: [senderId], references: [id], onDelete: Cascade)
  poll       ChatPoll?

  @@index([roomId, createdAt])
  @@index([roomId, isPinned, pinnedAt])
}

model ChatPoll {
  id             String           @id @default(uuid())
  messageId      String           @unique
  question       String
  allowsMultiple Boolean          @default(false)
  isAnonymous    Boolean          @default(false)
  closedAt       DateTime?
  message        ChatMessage      @relation(fields: [messageId], references: [id], onDelete: Cascade)
  options        ChatPollOption[]
}

model ChatPollOption {
  id     String         @id @default(uuid())
  pollId String
  text   String
  poll   ChatPoll       @relation(fields: [pollId], references: [id], onDelete: Cascade)
  votes  ChatPollVote[]
}

model ChatPollVote {
  id       String         @id @default(uuid())
  optionId String
  userId   String
  option   ChatPollOption @relation(fields: [optionId], references: [id], onDelete: Cascade)
  user     User           @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([optionId, userId])
}

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

  @@unique([groupId, userId])
}

model Address {
  id          String   @id @default(uuid())
  userId      String
  label       String
  city        String
  street      String
  house       String
  apartment   String?
  comment     String?
  latitude    Float?
  longitude   Float?
  fullAddress String?
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, label])
}

model SystemSetting {
  id          String   @id @default(uuid())
  key         String   @unique
  value       String
  description String?
  isSecret    Boolean  @default(false)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

model SocialProvider {
  id           String   @id @default(uuid())
  providerName String   @unique
  clientId     String
  clientSecret String?
  isEnabled    Boolean  @default(false)
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
}

model Bot {
  id           String      @id @default(uuid())
  name         String
  username     String      @unique
  tokenHash    String      @unique
  tokenPrefix  String
  ownerId      String
  description  String?
  aboutText    String?
  botPicUrl    String?
  menuButton   Json?
  webAppUrl    String?
  webhookUrl   String?
  webhookSecretToken String?
  isActive     Boolean     @default(true)
  isSystemBot  Boolean     @default(false)
  nextMessageId Int        @default(1)
  nextUpdateId  Int        @default(1)
  createdAt    DateTime    @default(now())
  updatedAt    DateTime    @updatedAt
  owner        User        @relation("BotOwner", fields: [ownerId], references: [id], onDelete: Cascade)
  linkedSystemUser User?   @relation("BotSystemUser")
  chats        BotChat[]
  messages     BotMessage[]
  inboundMessages BotInboundMessage[]
  updates      BotUpdate[]
  chatMenuButtons ChatMenuButton[]

  @@index([ownerId])
  @@index([tokenHash])
  @@index([isActive])
}

model BotChat {
  id              String       @id @default(uuid())
  botId           String
  recipientUserId String?
  roomId          String?
  telegramChatId  BigInt
  chatType        String       @default("private")
  nextInboundMessageId Int     @default(1)
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt
  bot             Bot          @relation(fields: [botId], references: [id], onDelete: Cascade)
  room            ChatRoom?    @relation(fields: [roomId], references: [id], onDelete: Cascade)
  messages        BotMessage[]
  inboundMessages BotInboundMessage[]
  menuButton      ChatMenuButton?

  @@unique([botId, recipientUserId])
  @@unique([botId, roomId])
  @@unique([botId, telegramChatId])
  @@index([botId])
  @@index([roomId])
}

model ChatMenuButton {
  id         String   @id @default(uuid())
  botId      String
  botChatId  String   @unique
  menuButton Json
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt
  bot        Bot      @relation(fields: [botId], references: [id], onDelete: Cascade)
  botChat    BotChat  @relation(fields: [botChatId], references: [id], onDelete: Cascade)

  @@unique([botId, botChatId])
  @@index([botId])
}

model BotMessage {
  id            String   @id @default(uuid())
  botId         String
  botChatId     String
  telegramMsgId Int
  messageType   String   @default("text")
  text          String?
  mediaUrl      String?
  payload       Json?
  isPinned      Boolean  @default(false)
  pinnedAt      DateTime?
  createdAt     DateTime @default(now())
  editedAt      DateTime?
  bot           Bot      @relation(fields: [botId], references: [id], onDelete: Cascade)
  botChat       BotChat  @relation(fields: [botChatId], references: [id], onDelete: Cascade)

  @@unique([botId, telegramMsgId])
  @@index([botChatId])
  @@index([botChatId, isPinned, pinnedAt])
}

model BotInboundMessage {
  id              String   @id @default(uuid())
  botId           String
  botChatId       String
  senderUserId    String
  telegramMsgId   Int
  text            String?
  payload         Json?
  createdAt       DateTime @default(now())
  bot             Bot      @relation(fields: [botId], references: [id], onDelete: Cascade)
  botChat         BotChat  @relation(fields: [botChatId], references: [id], onDelete: Cascade)

  @@unique([botChatId, telegramMsgId])
  @@index([botId, createdAt])
}

model BotUpdate {
  id        String   @id @default(uuid())
  botId     String
  updateId  Int
  payload   Json
  createdAt DateTime @default(now())
  bot       Bot      @relation(fields: [botId], references: [id], onDelete: Cascade)

  @@unique([botId, updateId])
  @@index([botId, updateId])
}
