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

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

// ============ Users & Auth ============

model User {
  id              BigInt    @id @default(autoincrement())
  username        String    @unique @db.VarChar(64)
  userType        String    @map("user_type") @db.VarChar(20)
  status          String    @default("ACTIVE") @db.VarChar(20)
  parentId        BigInt?   @map("parent_id")
  agentLevel      Int?      @map("agent_level")
  locale          String    @default("en-US") @db.VarChar(10)
  inviteCode      String?   @unique @map("invite_code") @db.VarChar(16)
  inviteSponsorId BigInt?   @map("invite_sponsor_id")
  usedInviteId    BigInt?   @map("used_invite_id")
  createdAt       DateTime  @default(now()) @map("created_at")
  updatedAt       DateTime  @updatedAt @map("updated_at")
  deletedAt       DateTime? @map("deleted_at")
  visibleMenus    String?   @map("visible_menus") @db.VarChar(1000)

  auth          UserAuth?
  wallet        Wallet?
  agentProfile  AgentProfile?
  adminRole     AdminUserRole?
  bets          Bet[]
  preferences   UserPreference?
  depositOrders DepositOrder[]  @relation("PlayerDepositOrders")
  playerMessages PlayerMessage[]

  parent         User?        @relation("UserHierarchy", fields: [parentId], references: [id])
  children       User[]       @relation("UserHierarchy")
  inviteSponsor  User?        @relation("InviteSponsor", fields: [inviteSponsorId], references: [id])
  invitedPlayers User[]       @relation("InviteSponsor")
  usedInvite     UserInvite?  @relation("UsedInvite", fields: [usedInviteId], references: [id])
  invites        UserInvite[] @relation("UserInvites")

  @@index([userType])
  @@index([parentId])
  @@index([inviteSponsorId])
  @@index([usedInviteId])
  @@map("users")
}

model UserInvite {
  id            BigInt    @id @default(autoincrement())
  code          String    @unique @db.VarChar(16)
  sponsorId     BigInt    @map("sponsor_id")
  status        String    @default("ACTIVE") @db.VarChar(20)
  registerCount Int       @default(0) @map("register_count")
  createdAt     DateTime  @default(now()) @map("created_at")
  revokedAt     DateTime? @map("revoked_at")
  cashbackRate  Decimal?  @map("cashback_rate") @db.Decimal(8, 4)

  sponsor       User   @relation("UserInvites", fields: [sponsorId], references: [id])
  registrations User[] @relation("UsedInvite")

  @@index([sponsorId])
  @@index([status])
  @@index([createdAt])
  @@map("user_invites")
}

model UserAuth {
  id             BigInt    @id @default(autoincrement())
  userId         BigInt    @unique @map("user_id")
  passwordHash   String    @map("password_hash") @db.VarChar(255)
  loginFailCount Int       @default(0) @map("login_fail_count")
  lockedUntil    DateTime? @map("locked_until")
  lastLoginAt    DateTime? @map("last_login_at")
  createdAt      DateTime  @default(now()) @map("created_at")
  updatedAt      DateTime  @updatedAt @map("updated_at")

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

  @@map("user_auth")
}

model UserPreference {
  id                  BigInt   @id @default(autoincrement())
  userId              BigInt   @unique @map("user_id")
  locale              String   @default("en-US") @db.VarChar(10)
  phone               String?  @db.VarChar(32)
  phoneCountryDial    String?  @map("phone_country_dial") @db.VarChar(8)
  phoneLocal          String?  @map("phone_local") @db.VarChar(24)
  email               String?  @db.VarChar(128)
  avatarKey           String?  @map("avatar_key") @db.VarChar(128)
  allowPasswordChange Boolean  @default(true) @map("allow_password_change")
  allowUsernameChange Boolean  @default(false) @map("allow_username_change")
  managedPassword     String?  @map("managed_password") @db.VarChar(128)
  createdAt           DateTime @default(now()) @map("created_at")
  updatedAt           DateTime @updatedAt @map("updated_at")

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

  @@index([phoneCountryDial, phoneLocal])
  @@map("user_preferences")
}

model Role {
  id          BigInt   @id @default(autoincrement())
  code        String   @unique @db.VarChar(64)
  name        String   @db.VarChar(128)
  description String?  @db.VarChar(255)
  createdAt   DateTime @default(now()) @map("created_at")

  permissions RolePermission[]
  adminUsers  AdminUserRole[]

  @@map("roles")
}

model Permission {
  id        BigInt   @id @default(autoincrement())
  code      String   @unique @db.VarChar(128)
  name      String   @db.VarChar(128)
  module    String   @db.VarChar(64)
  createdAt DateTime @default(now()) @map("created_at")

  roles RolePermission[]

  @@map("permissions")
}

model RolePermission {
  roleId       BigInt @map("role_id")
  permissionId BigInt @map("permission_id")

  role       Role       @relation(fields: [roleId], references: [id])
  permission Permission @relation(fields: [permissionId], references: [id])

  @@id([roleId, permissionId])
  @@map("role_permissions")
}

model AdminUserRole {
  userId    BigInt   @unique @map("user_id")
  roleId    BigInt   @map("role_id")
  createdAt DateTime @default(now()) @map("created_at")

  user User @relation(fields: [userId], references: [id])
  role Role @relation(fields: [roleId], references: [id])

  @@map("admin_user_roles")
}

// ============ Agent ============

model AgentProfile {
  id                     BigInt   @id @default(autoincrement())
  userId                 BigInt   @unique @map("user_id")
  level                  Int
  parentAgentId          BigInt?  @map("parent_agent_id")
  creditLimit            Decimal  @default(0) @map("credit_limit") @db.Decimal(18, 4)
  usedCredit             Decimal  @default(0) @map("used_credit") @db.Decimal(18, 4)
  directPlayerLiability  Decimal  @default(0) @map("direct_player_liability") @db.Decimal(18, 4)
  childAgentExposure     Decimal  @default(0) @map("child_agent_exposure") @db.Decimal(18, 4)
  status                 String   @default("ACTIVE") @db.VarChar(20)
  maxSingleDeposit       Decimal? @map("max_single_deposit") @db.Decimal(18, 4)
  maxDailyDeposit        Decimal? @map("max_daily_deposit") @db.Decimal(18, 4)
  cashbackRate           Decimal  @default(0) @map("cashback_rate") @db.Decimal(8, 4)
  blockDirectPlayerLogin Boolean  @default(false) @map("block_direct_player_login")
  createdAt              DateTime @default(now()) @map("created_at")
  updatedAt              DateTime @updatedAt @map("updated_at")

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

  @@index([parentAgentId])
  @@map("agent_profiles")
}

model AgentClosure {
  ancestorId   BigInt @map("ancestor_id")
  descendantId BigInt @map("descendant_id")
  depth        Int

  @@id([ancestorId, descendantId])
  @@index([descendantId])
  @@map("agent_closure")
}

model AgentCreditTransaction {
  id              BigInt   @id @default(autoincrement())
  agentId         BigInt   @map("agent_id")
  transactionType String   @map("transaction_type") @db.VarChar(32)
  amount          Decimal  @db.Decimal(18, 4)
  creditBefore    Decimal  @map("credit_before") @db.Decimal(18, 4)
  creditAfter     Decimal  @map("credit_after") @db.Decimal(18, 4)
  referenceType   String?  @map("reference_type") @db.VarChar(32)
  referenceId     String?  @map("reference_id") @db.VarChar(64)
  operatorId      BigInt?  @map("operator_id")
  requestId       String?  @map("request_id") @db.VarChar(128)
  remark          String?  @db.VarChar(500)
  createdAt       DateTime @default(now()) @map("created_at")

  @@unique([operatorId, requestId])
  @@index([agentId])
  @@map("agent_credit_transactions")
}

// ============ Wallet ============

model Wallet {
  id               BigInt   @id @default(autoincrement())
  userId           BigInt   @unique @map("user_id")
  availableBalance Decimal  @default(0) @map("available_balance") @db.Decimal(18, 4)
  frozenBalance    Decimal  @default(0) @map("frozen_balance") @db.Decimal(18, 4)
  currency         String   @default("USD") @db.VarChar(16)
  status           String   @default("ACTIVE") @db.VarChar(20)
  version          Int      @default(0)
  createdAt        DateTime @default(now()) @map("created_at")
  updatedAt        DateTime @updatedAt @map("updated_at")

  user         User                @relation(fields: [userId], references: [id])
  transactions WalletTransaction[]

  @@map("wallets")
}

model WalletTransaction {
  id              BigInt   @id @default(autoincrement())
  transactionId   String   @unique @map("transaction_id") @db.VarChar(64)
  userId          BigInt   @map("user_id")
  walletId        BigInt   @map("wallet_id")
  transactionType String   @map("transaction_type") @db.VarChar(32)
  amount          Decimal  @db.Decimal(18, 4)
  balanceBefore   Decimal  @map("balance_before") @db.Decimal(18, 4)
  balanceAfter    Decimal  @map("balance_after") @db.Decimal(18, 4)
  frozenBefore    Decimal  @map("frozen_before") @db.Decimal(18, 4)
  frozenAfter     Decimal  @map("frozen_after") @db.Decimal(18, 4)
  referenceType   String?  @map("reference_type") @db.VarChar(32)
  referenceId     String?  @map("reference_id") @db.VarChar(64)
  businessKey     String?  @unique @map("business_key") @db.VarChar(128)
  operatorId      BigInt?  @map("operator_id")
  remark          String?  @db.VarChar(500)
  createdAt       DateTime @default(now()) @map("created_at")

  wallet Wallet @relation(fields: [walletId], references: [id])

  @@index([userId])
  @@index([walletId])
  @@index([createdAt])
  @@map("wallet_transactions")
}

// ============ Sports Data ============

model League {
  id           BigInt    @id @default(autoincrement())
  sportType    String    @default("FOOTBALL") @map("sport_type") @db.VarChar(20)
  code         String    @unique @db.VarChar(64)
  logoUrl      String?   @map("logo_url") @db.VarChar(500)
  displayOrder Int       @default(0) @map("display_order")
  isActive     Boolean   @default(true) @map("is_active")
  createdAt    DateTime  @default(now()) @map("created_at")
  updatedAt    DateTime  @updatedAt @map("updated_at")
  deletedAt    DateTime? @map("deleted_at")

  matches Match[]

  @@map("leagues")
}

model Team {
  id         BigInt    @id @default(autoincrement())
  sportType  String    @default("FOOTBALL") @map("sport_type") @db.VarChar(20)
  code       String    @unique @db.VarChar(64)
  externalId Int?      @unique @map("external_id")
  logoUrl    String?   @map("logo_url") @db.VarChar(500)
  createdAt  DateTime  @default(now()) @map("created_at")
  updatedAt  DateTime  @updatedAt @map("updated_at")
  deletedAt  DateTime? @map("deleted_at")

  homeMatches Match[] @relation("HomeTeam")
  awayMatches Match[] @relation("AwayTeam")

  @@map("teams")
}

model EntityTranslation {
  id         BigInt   @id @default(autoincrement())
  entityType String   @map("entity_type") @db.VarChar(32)
  entityId   BigInt   @map("entity_id")
  locale     String   @db.VarChar(10)
  fieldName  String   @map("field_name") @db.VarChar(32)
  value      String   @db.VarChar(500)
  createdAt  DateTime @default(now()) @map("created_at")
  updatedAt  DateTime @updatedAt @map("updated_at")

  @@unique([entityType, entityId, locale, fieldName])
  @@index([entityType, entityId])
  @@map("entity_translations")
}

model Match {
  id              BigInt    @id @default(autoincrement())
  sportType       String    @default("FOOTBALL") @map("sport_type") @db.VarChar(20)
  leagueId        BigInt    @map("league_id")
  homeTeamId      BigInt    @map("home_team_id")
  awayTeamId      BigInt    @map("away_team_id")
  startTime       DateTime  @map("start_time")
  status          String    @default("DRAFT") @db.VarChar(32)
  isHot           Boolean   @default(false) @map("is_hot")
  displayOrder    Int       @default(0) @map("display_order")
  publishTime     DateTime? @map("publish_time")
  closeTime       DateTime? @map("close_time")
  isOutright      Boolean   @default(false) @map("is_outright")
  officialMatchNo Int?      @map("official_match_no")
  stage           String?   @db.VarChar(32)
  groupName       String?   @map("group_name") @db.VarChar(8)
  liveMatchId     BigInt?   @unique @map("live_match_id")
  additionMatchId BigInt?   @map("addition_match_id")
  channelId       String?   @map("channel_id") @db.VarChar(64)
  matchName       String?   @map("match_name") @db.VarChar(200)
  venueJson       Json?     @map("venue_json")
  kickoffJson     Json?     @map("kickoff_json")
  externalStatus  String?   @map("external_status") @db.VarChar(32)
  createdBy       BigInt?   @map("created_by")
  updatedBy       BigInt?   @map("updated_by")
  createdAt       DateTime  @default(now()) @map("created_at")
  updatedAt       DateTime  @updatedAt @map("updated_at")
  deletedAt       DateTime? @map("deleted_at")

  league      League            @relation(fields: [leagueId], references: [id])
  homeTeam    Team              @relation("HomeTeam", fields: [homeTeamId], references: [id])
  awayTeam    Team              @relation("AwayTeam", fields: [awayTeamId], references: [id])
  score       MatchScore?
  markets     Market[]
  settlements SettlementBatch[]

  @@index([status])
  @@index([startTime])
  @@index([leagueId])
  @@map("matches")
}

model MatchScore {
  id              BigInt   @id @default(autoincrement())
  matchId         BigInt   @unique @map("match_id")
  htHomeScore     Int?     @map("ht_home_score")
  htAwayScore     Int?     @map("ht_away_score")
  ftHomeScore     Int?     @map("ft_home_score")
  ftAwayScore     Int?     @map("ft_away_score")
  homeCorners     Int?     @map("home_corners")
  awayCorners     Int?     @map("away_corners")
  homeYellowCards Int?     @map("home_yellow_cards")
  awayYellowCards Int?     @map("away_yellow_cards")
  homeRedCards    Int?     @map("home_red_cards")
  awayRedCards    Int?     @map("away_red_cards")
  homeCards       Int?     @map("home_cards")
  awayCards       Int?     @map("away_cards")
  winnerTeamId    BigInt?  @map("winner_team_id")
  recordedBy      BigInt?  @map("recorded_by")
  createdAt       DateTime @default(now()) @map("created_at")
  updatedAt       DateTime @updatedAt @map("updated_at")

  match Match @relation(fields: [matchId], references: [id])

  @@map("match_scores")
}

model Market {
  id             BigInt   @id @default(autoincrement())
  matchId        BigInt   @map("match_id")
  marketType     String   @map("market_type") @db.VarChar(64)
  marketKey      String?  @map("market_key") @db.VarChar(64)
  lineKey        String?  @map("line_key") @db.VarChar(180)
  period         String   @db.VarChar(16)
  lineValue      Decimal? @map("line_value") @db.Decimal(8, 2)
  paramsJson     Json?    @map("params_json")
  status         String   @default("OPEN") @db.VarChar(20)
  allowSingle    Boolean  @default(true) @map("allow_single")
  allowParlay    Boolean  @default(true) @map("allow_parlay")
  showOnPlayer   Boolean  @default(true) @map("show_on_player")
  sortOrder      Int      @default(0) @map("sort_order")
  promoLabel     String?  @map("promo_label") @db.VarChar(100)
  promoLabelI18n Json?    @map("promo_label_i18n")
  nameI18n       Json?    @map("name_i18n")
  templateItemId BigInt?  @map("template_item_id")
  createdAt      DateTime @default(now()) @map("created_at")
  updatedAt      DateTime @updatedAt @map("updated_at")

  match      Match             @relation(fields: [matchId], references: [id])
  selections MarketSelection[]

  @@index([matchId])
  @@index([matchId, lineKey])
  @@index([marketType])
  @@map("markets")
}

model MarketSelection {
  id            BigInt   @id @default(autoincrement())
  marketId      BigInt   @map("market_id")
  selectionCode String   @map("selection_code") @db.VarChar(64)
  selectionName String   @map("selection_name") @db.VarChar(255)
  nameI18n      Json?    @map("name_i18n")
  odds          Decimal  @db.Decimal(18, 6)
  oddsVersion   BigInt   @default(1) @map("odds_version")
  status        String   @default("OPEN") @db.VarChar(20)
  sortOrder     Int      @default(0) @map("sort_order")
  createdAt     DateTime @default(now()) @map("created_at")
  updatedAt     DateTime @updatedAt @map("updated_at")

  market   Market          @relation(fields: [marketId], references: [id])
  oddsLogs OddsChangeLog[]

  @@index([marketId])
  @@map("market_selections")
}

model MarketTemplate {
  id          BigInt   @id @default(autoincrement())
  sportType   String   @default("FOOTBALL") @map("sport_type") @db.VarChar(20)
  name        String   @db.VarChar(128)
  nameI18n    Json?    @map("name_i18n")
  description String?  @db.VarChar(500)
  isDefault   Boolean  @default(false) @map("is_default")
  status      String   @default("ACTIVE") @db.VarChar(20)
  sortOrder   Int      @default(0) @map("sort_order")
  createdAt   DateTime @default(now()) @map("created_at")
  updatedAt   DateTime @updatedAt @map("updated_at")

  items MarketTemplateItem[]

  @@index([sportType, status])
  @@index([isDefault])
  @@map("market_templates")
}

model MarketTemplateItem {
  id             BigInt   @id @default(autoincrement())
  templateId     BigInt   @map("template_id")
  marketType     String   @map("market_type") @db.VarChar(64)
  marketKey      String?  @map("market_key") @db.VarChar(64)
  lineKey        String   @map("line_key") @db.VarChar(180)
  period         String   @db.VarChar(16)
  lineValue      Decimal? @map("line_value") @db.Decimal(8, 2)
  paramsJson     Json?    @map("params_json")
  status         String   @default("OPEN") @db.VarChar(20)
  allowSingle    Boolean  @default(true) @map("allow_single")
  allowParlay    Boolean  @default(true) @map("allow_parlay")
  showOnPlayer   Boolean  @default(true) @map("show_on_player")
  sortOrder      Int      @default(0) @map("sort_order")
  promoLabel     String?  @map("promo_label") @db.VarChar(100)
  promoLabelI18n Json?    @map("promo_label_i18n")
  nameI18n       Json?    @map("name_i18n")
  createdAt      DateTime @default(now()) @map("created_at")
  updatedAt      DateTime @updatedAt @map("updated_at")

  template   MarketTemplate            @relation(fields: [templateId], references: [id], onDelete: Cascade)
  selections MarketTemplateSelection[]

  @@unique([templateId, lineKey])
  @@index([templateId])
  @@index([marketType])
  @@map("market_template_items")
}

model MarketTemplateSelection {
  id             BigInt   @id @default(autoincrement())
  templateItemId BigInt   @map("template_item_id")
  selectionCode  String   @map("selection_code") @db.VarChar(64)
  selectionName  String   @map("selection_name") @db.VarChar(255)
  nameI18n       Json?    @map("name_i18n")
  odds           Decimal  @db.Decimal(18, 6)
  status         String   @default("OPEN") @db.VarChar(20)
  sortOrder      Int      @default(0) @map("sort_order")
  createdAt      DateTime @default(now()) @map("created_at")
  updatedAt      DateTime @updatedAt @map("updated_at")

  item MarketTemplateItem @relation(fields: [templateItemId], references: [id], onDelete: Cascade)

  @@unique([templateItemId, selectionCode])
  @@index([templateItemId])
  @@map("market_template_selections")
}

model OddsChangeLog {
  id          BigInt   @id @default(autoincrement())
  selectionId BigInt   @map("selection_id")
  oldOdds     Decimal  @map("old_odds") @db.Decimal(18, 6)
  newOdds     Decimal  @map("new_odds") @db.Decimal(18, 6)
  oddsVersion BigInt   @map("odds_version")
  changedBy   BigInt?  @map("changed_by")
  createdAt   DateTime @default(now()) @map("created_at")

  selection MarketSelection @relation(fields: [selectionId], references: [id])

  @@index([selectionId])
  @@map("odds_change_logs")
}

// ============ Bets ============

model Bet {
  id               BigInt    @id @default(autoincrement())
  betNo            String    @unique @map("bet_no") @db.VarChar(64)
  userId           BigInt    @map("user_id")
  agentId          BigInt?   @map("agent_id")
  betType          String    @map("bet_type") @db.VarChar(20)
  stake            Decimal   @db.Decimal(18, 4)
  totalOdds        Decimal?  @map("total_odds") @db.Decimal(18, 6)
  potentialReturn  Decimal?  @map("potential_return") @db.Decimal(18, 4)
  actualReturn     Decimal   @default(0) @map("actual_return") @db.Decimal(18, 4)
  status           String    @default("PENDING") @db.VarChar(32)
  settlementStatus String?   @map("settlement_status") @db.VarChar(32)
  currency         String    @default("USD") @db.VarChar(16)
  requestId        String    @map("request_id") @db.VarChar(128)
  placedAt         DateTime  @default(now()) @map("placed_at")
  settledAt        DateTime? @map("settled_at")
  isCashbacked     Boolean   @default(false) @map("is_cashbacked")
  createdAt        DateTime  @default(now()) @map("created_at")
  updatedAt        DateTime  @updatedAt @map("updated_at")

  user           User           @relation(fields: [userId], references: [id])
  selections     BetSelection[]
  cashbackClaims CashbackBet[]

  @@unique([userId, requestId])
  @@index([userId])
  @@index([agentId])
  @@index([status])
  @@index([placedAt])
  @@map("bets")
}

model BetSelection {
  id                    BigInt   @id @default(autoincrement())
  betId                 BigInt   @map("bet_id")
  matchId               BigInt?  @map("match_id")
  marketId              BigInt   @map("market_id")
  selectionId           BigInt   @map("selection_id")
  marketType            String   @map("market_type") @db.VarChar(64)
  period                String?  @db.VarChar(16)
  marketNameSnapshot    String?  @map("market_name_snapshot") @db.VarChar(255)
  selectionNameSnapshot String   @map("selection_name_snapshot") @db.VarChar(255)
  handicapLine          Decimal? @map("handicap_line") @db.Decimal(8, 2)
  totalLine             Decimal? @map("total_line") @db.Decimal(8, 2)
  odds                  Decimal  @db.Decimal(18, 6)
  oddsVersion           BigInt   @map("odds_version")
  resultStatus          String?  @map("result_status") @db.VarChar(32)
  effectiveOdds         Decimal? @map("effective_odds") @db.Decimal(18, 6)
  sortOrder             Int      @default(0) @map("sort_order")
  createdAt             DateTime @default(now()) @map("created_at")

  bet Bet @relation(fields: [betId], references: [id])

  @@index([betId])
  @@index([matchId])
  @@map("bet_selections")
}

// ============ Settlement ============

model SettlementBatch {
  id              BigInt    @id @default(autoincrement())
  matchId         BigInt    @map("match_id")
  batchNo         String    @unique @map("batch_no") @db.VarChar(64)
  htHomeScore     Int?      @map("ht_home_score")
  htAwayScore     Int?      @map("ht_away_score")
  ftHomeScore     Int?      @map("ft_home_score")
  ftAwayScore     Int?      @map("ft_away_score")
  homeCorners     Int?      @map("home_corners")
  awayCorners     Int?      @map("away_corners")
  homeYellowCards Int?      @map("home_yellow_cards")
  awayYellowCards Int?      @map("away_yellow_cards")
  homeRedCards    Int?      @map("home_red_cards")
  awayRedCards    Int?      @map("away_red_cards")
  homeCards       Int?      @map("home_cards")
  awayCards       Int?      @map("away_cards")
  status          String    @default("PREVIEW") @db.VarChar(20)
  totalBets       Int       @default(0) @map("total_bets")
  totalPayout     Decimal   @default(0) @map("total_payout") @db.Decimal(18, 4)
  totalRefund     Decimal   @default(0) @map("total_refund") @db.Decimal(18, 4)
  operatorId      BigInt?   @map("operator_id")
  confirmedAt     DateTime? @map("confirmed_at")
  isResettle      Boolean   @default(false) @map("is_resettle")
  reason          String?   @db.VarChar(500)
  createdAt       DateTime  @default(now()) @map("created_at")

  match Match            @relation(fields: [matchId], references: [id])
  items SettlementItem[]

  @@index([matchId])
  @@map("settlement_batches")
}

model SettlementItem {
  id        BigInt   @id @default(autoincrement())
  batchId   BigInt   @map("batch_id")
  betId     BigInt   @map("bet_id")
  userId    BigInt   @map("user_id")
  result    String   @db.VarChar(32)
  payout    Decimal  @db.Decimal(18, 4)
  createdAt DateTime @default(now()) @map("created_at")

  batch SettlementBatch @relation(fields: [batchId], references: [id])

  @@unique([batchId, betId])
  @@index([batchId])
  @@index([betId])
  @@map("settlement_items")
}

// ============ Cashback ============

model CashbackRule {
  id         BigInt   @id @default(autoincrement())
  name       String   @db.VarChar(128)
  targetType String   @map("target_type") @db.VarChar(32)
  targetId   BigInt?  @map("target_id")
  rate       Decimal  @db.Decimal(8, 4)
  marketType String?  @map("market_type") @db.VarChar(64)
  isActive   Boolean  @default(true) @map("is_active")
  createdAt  DateTime @default(now()) @map("created_at")
  updatedAt  DateTime @updatedAt @map("updated_at")

  @@map("cashback_rules")
}

model CashbackBatch {
  id                  BigInt    @id @default(autoincrement())
  batchNo             String    @unique @map("batch_no") @db.VarChar(64)
  periodStart         DateTime  @map("period_start")
  periodEnd           DateTime  @map("period_end")
  status              String    @default("PREVIEW") @db.VarChar(20)
  totalAmount         Decimal   @default(0) @map("total_amount") @db.Decimal(18, 4)
  totalEffectiveStake Decimal   @default(0) @map("total_effective_stake") @db.Decimal(18, 4)
  totalBetCount       Int       @default(0) @map("total_bet_count")
  playerCount         Int       @default(0) @map("player_count")
  operatorId          BigInt?   @map("operator_id")
  confirmedAt         DateTime? @map("confirmed_at")
  createdAt           DateTime  @default(now()) @map("created_at")

  items CashbackItem[]
  bets  CashbackBet[]

  @@map("cashback_batches")
}

model CashbackItem {
  id             BigInt   @id @default(autoincrement())
  batchId        BigInt   @map("batch_id")
  userId         BigInt   @map("user_id")
  effectiveStake Decimal  @map("effective_stake") @db.Decimal(18, 4)
  betCount       Int      @default(0) @map("bet_count")
  rate           Decimal  @db.Decimal(8, 4)
  amount         Decimal  @db.Decimal(18, 4)
  createdAt      DateTime @default(now()) @map("created_at")

  batch CashbackBatch @relation(fields: [batchId], references: [id])

  @@index([batchId])
  @@index([userId])
  @@map("cashback_items")
}

/**
 * 返水批次占用的注单（每笔注单全局仅能计入一次待发放/已发放批次）
 */
model CashbackBet {
  id        BigInt   @id @default(autoincrement())
  batchId   BigInt   @map("batch_id")
  betId     BigInt   @unique @map("bet_id")
  userId    BigInt   @map("user_id")
  stake     Decimal  @db.Decimal(18, 4)
  amount    Decimal  @db.Decimal(18, 4)
  createdAt DateTime @default(now()) @map("created_at")

  batch CashbackBatch @relation(fields: [batchId], references: [id], onDelete: Cascade)
  bet   Bet           @relation(fields: [betId], references: [id])

  @@index([batchId])
  @@index([userId])
  @@map("cashback_bets")
}

// ============ Content & i18n ============

model Content {
  id          BigInt    @id @default(autoincrement())
  contentType String    @map("content_type") @db.VarChar(32)
  sortOrder   Int       @default(0) @map("sort_order")
  status      String    @default("DRAFT") @db.VarChar(20)
  linkType    String?   @map("link_type") @db.VarChar(32)
  linkTarget  String?   @map("link_target") @db.VarChar(500)
  startTime   DateTime? @map("start_time")
  endTime     DateTime? @map("end_time")
  createdAt   DateTime  @default(now()) @map("created_at")
  updatedAt   DateTime  @updatedAt @map("updated_at")

  translations ContentTranslation[]

  @@index([contentType, status])
  @@map("contents")
}

model ContentTranslation {
  id        BigInt  @id @default(autoincrement())
  contentId BigInt  @map("content_id")
  locale    String  @db.VarChar(10)
  title     String? @db.VarChar(255)
  body      String? @db.Text
  imageUrl  String? @map("image_url") @db.VarChar(500)

  content Content @relation(fields: [contentId], references: [id])

  @@unique([contentId, locale])
  @@map("content_translations")
}

model I18nMessage {
  id        BigInt   @id @default(autoincrement())
  msgKey    String   @map("msg_key") @db.VarChar(128)
  locale    String   @db.VarChar(10)
  value     String   @db.Text
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@unique([msgKey, locale])
  @@map("i18n_messages")
}

// ============ Media / File Uploads ============

model UploadedFile {
  id         String   @id @default(uuid())
  filename   String   @unique
  category   String   @db.VarChar(32)
  mimeType   String   @map("mime_type") @db.VarChar(64)
  size       Int
  url        String   @db.VarChar(500)
  uploadedBy BigInt?  @map("uploaded_by")
  createdAt  DateTime @default(now()) @map("created_at")

  @@index([category])
  @@map("uploaded_files")
}

// ============ Manual Deposit / Recharge ============

model PaymentMethod {
  id            BigInt   @id @default(autoincrement())
  methodType    String   @map("method_type") @db.VarChar(20)
  bankName      String?  @map("bank_name") @db.VarChar(128)
  accountHolder String?  @map("account_holder") @db.VarChar(128)
  accountNumber String?  @map("account_number") @db.VarChar(128)
  usdtAddress   String?  @map("usdt_address") @db.VarChar(256)
  qrCodeUrl     String?  @map("qr_code_url") @db.VarChar(500)
  displayName   String?  @map("display_name") @db.VarChar(128)
  sortOrder     Int      @default(0) @map("sort_order")
  isActive      Boolean  @default(true) @map("is_active")
  showOnPlayer  Boolean  @default(true) @map("show_on_player")
  createdBy     BigInt?  @map("created_by")
  createdAt     DateTime @default(now()) @map("created_at")
  updatedAt     DateTime @updatedAt @map("updated_at")

  depositOrders DepositOrder[]

  @@index([methodType, isActive])
  @@map("payment_methods")
}

model DepositOrder {
  id              BigInt    @id @default(autoincrement())
  orderNo         String    @unique @map("order_no") @db.VarChar(64)
  playerId        BigInt    @map("player_id")
  paymentMethodId BigInt    @map("payment_method_id")
  methodType      String    @map("method_type") @db.VarChar(20)
  amount          Decimal   @db.Decimal(18, 4)
  screenshotUrl   String    @map("screenshot_url") @db.VarChar(500)
  status          String    @default("PENDING") @db.VarChar(20)
  approvedAmount  Decimal?  @map("approved_amount") @db.Decimal(18, 4)
  reviewerId      BigInt?   @map("reviewer_id")
  reviewedAt      DateTime? @map("reviewed_at")
  rejectReason    String?   @map("reject_reason") @db.VarChar(500)
  remark          String?   @db.VarChar(500)
  createdAt       DateTime  @default(now()) @map("created_at")
  updatedAt       DateTime  @updatedAt @map("updated_at")

  player        User          @relation("PlayerDepositOrders", fields: [playerId], references: [id])
  paymentMethod PaymentMethod @relation(fields: [paymentMethodId], references: [id])
  auditLogs     DepositOrderAuditLog[]

  @@index([playerId])
  @@index([status])
  @@index([createdAt])
  @@map("deposit_orders")
}

model DepositOrderAuditLog {
  id             BigInt   @id @default(autoincrement())
  depositOrderId BigInt   @map("deposit_order_id")
  action         String   @db.VarChar(32)
  actorId        BigInt?  @map("actor_id")
  actorType      String   @map("actor_type") @db.VarChar(20)
  statusBefore   String?  @map("status_before") @db.VarChar(20)
  statusAfter    String   @map("status_after") @db.VarChar(20)
  amount         Decimal? @db.Decimal(18, 4)
  approvedAmount Decimal? @map("approved_amount") @db.Decimal(18, 4)
  remark         String?  @db.VarChar(500)
  createdAt      DateTime @default(now()) @map("created_at")

  depositOrder DepositOrder @relation(fields: [depositOrderId], references: [id], onDelete: Cascade)

  @@index([depositOrderId])
  @@index([createdAt])
  @@map("deposit_order_audit_logs")
}

model PlayerMessage {
  id          BigInt    @id @default(autoincrement())
  userId      BigInt    @map("user_id")
  type        String    @db.VarChar(32)
  title       String    @db.VarChar(256)
  body        String    @db.Text
  payload     Json?
  broadcastId BigInt?   @map("broadcast_id")
  readAt      DateTime? @map("read_at")
  createdAt   DateTime  @default(now()) @map("created_at")

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

  @@index([userId, createdAt(sort: Desc)])
  @@index([userId, readAt])
  @@index([broadcastId])
  @@map("player_messages")
}

model PlayerMessageBroadcast {
  id                BigInt   @id @default(autoincrement())
  title             String   @db.VarChar(256)
  body              String   @db.Text
  translations      Json?    @map("translations")
  targetType        String   @map("target_type") @db.VarChar(16)
  targetUserId      BigInt?  @map("target_user_id")
  targetUsername    String?  @map("target_username") @db.VarChar(64)
  recipientCount    Int      @default(0) @map("recipient_count")
  createdById       BigInt?  @map("created_by_id")
  createdByUsername String?  @map("created_by_username") @db.VarChar(64)
  createdAt         DateTime @default(now()) @map("created_at")

  messages PlayerMessage[]

  @@index([createdAt(sort: Desc)])
  @@map("player_message_broadcasts")
}

// ============ System Config & Audit ============

model SystemConfig {
  id          BigInt   @id @default(autoincrement())
  configKey   String   @unique @map("config_key") @db.VarChar(128)
  configValue String   @map("config_value") @db.Text
  description String?  @db.VarChar(255)
  updatedAt   DateTime @updatedAt @map("updated_at")

  @@map("system_configs")
}

model AuditLog {
  id           BigInt   @id @default(autoincrement())
  operatorId   BigInt?  @map("operator_id")
  operatorType String   @map("operator_type") @db.VarChar(20)
  action       String   @db.VarChar(128)
  module       String   @db.VarChar(64)
  targetType   String?  @map("target_type") @db.VarChar(32)
  targetId     String?  @map("target_id") @db.VarChar(64)
  beforeData   String?  @map("before_data") @db.Text
  afterData    String?  @map("after_data") @db.Text
  ipAddress    String?  @map("ip_address") @db.VarChar(45)
  userAgent    String?  @map("user_agent") @db.VarChar(500)
  createdAt    DateTime @default(now()) @map("created_at")

  @@index([operatorId])
  @@index([module])
  @@index([createdAt])
  @@map("audit_logs")
}
