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

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

model User {
  id                   String                      @id @default(uuid())
  discordId            String                      @unique
  discordName          String
  discordDiscriminator String
  discordAvatar        String?
  discordRefreshToken  String
  twitch               String?
  twitter              String?
  youtubeId            String?
  youtubeName          String?
  createdAt            DateTime                    @default(now())
  updatedAt            DateTime                    @updatedAt
  trustedUsers         TrustRelationships[]        @relation("trustGiver")
  trustingUsers        TrustRelationships[]        @relation("trustReceiver")
  ownedOrganization    Organization?
  tournamentTeams      TournamentTeamMember[]
  tournamentMatches    TournamentMatchGameResult[]
  lfgGroups            LfgGroupMember[]
  skill                Skill[]
}

model Organization {
  id            String       @id @default(uuid())
  name          String
  // Name in lower case to show in URL
  nameForUrl    String       @unique
  ownerId       String       @unique
  owner         User         @relation(fields: [ownerId], references: [id])
  discordInvite String
  twitter       String?
  tournaments   Tournament[]
}

model Tournament {
  id                String              @id @default(uuid())
  name              String
  // Name in lower case to show in URL
  nameForUrl        String
  description       String
  startTime         DateTime
  checkInStartTime  DateTime
  // CSS for tournament banner's background value
  bannerBackground  String
  // CSS for tournament banner's color value
  bannerTextHSLArgs String
  // Team ID's in an array in the order of the seed. 0 index is 1st seed, 1 index is 2nd seed etc.
  // Any team not in the list will be at the bottom in the order of their createdAt time stamp
  // (older teams first)
  seeds             String[]
  mapPool           Stage[]
  organizerId       String
  organizer         Organization        @relation(fields: [organizerId], references: [id])
  teams             TournamentTeam[]
  brackets          TournamentBracket[]
  changedSkills     Skill[]

  // There might be duplicate nameForUrl's but inside an organization they're unique
  @@unique([nameForUrl, organizerId])
}

enum Mode {
  TW
  SZ
  TC
  RM
  CB
}

model Stage {
  id                 Int                    @id @default(autoincrement())
  name               String
  mode               Mode
  tournamentMapPools Tournament[]
  tournamentRounds   TournamentRoundStage[]
  lfgGroupMatches    LfgGroupMatchStage[]
}

model TournamentTeam {
  id            String                       @id @default(uuid())
  name          String
  tournamentId  String
  canHost       Boolean                      @default(true)
  friendCode    String
  roomPass      String?
  inviteCode    String                       @default(uuid())
  checkedInTime DateTime?
  createdAt     DateTime                     @default(now())
  tournament    Tournament                   @relation(fields: [tournamentId], references: [id])
  members       TournamentTeamMember[]
  matches       TournamentMatchParticipant[]

  @@unique([name, tournamentId])
}

model TournamentTeamMember {
  memberId     String
  teamId       String
  tournamentId String
  captain      Boolean        @default(false)
  team         TournamentTeam @relation(fields: [teamId], references: [id])
  member       User           @relation(fields: [memberId], references: [id])

  @@unique([memberId, tournamentId])
}

// Trust relationship is defined as user allowing another user
// to add them to a tournament team
// / LFG group without them having to click a link.
model TrustRelationships {
  trustGiverId    String
  trustReceiverId String
  trustGiver      User     @relation("trustGiver", fields: [trustGiverId], references: [id])
  trustReceiver   User     @relation("trustReceiver", fields: [trustReceiverId], references: [id])
  createdAt       DateTime @default(now())

  @@unique([trustGiverId, trustReceiverId])
}

enum BracketType {
  SE
  DE
}

model TournamentBracket {
  id           String            @id @default(uuid())
  tournamentId String
  type         BracketType
  rounds       TournamentRound[]
  tournament   Tournament        @relation(fields: [tournamentId], references: [id])
}

model TournamentRound {
  id        String                 @id @default(uuid())
  // position of the round 1 for Round 1, 2 for Round 2, -1 for Losers Round 1 etc.
  position  Int
  bracketId String
  bracket   TournamentBracket      @relation(fields: [bracketId], references: [id])
  matches   TournamentMatch[]
  stages    TournamentRoundStage[]
}

model TournamentRoundStage {
  id       String                      @id @default(uuid())
  // position of the match 1 for Game 1, 2 for Game 2 etc.
  position Int
  roundId  String
  stageId  Int
  round    TournamentRound             @relation(fields: [roundId], references: [id])
  stage    Stage                       @relation(fields: [stageId], references: [id])
  results  TournamentMatchGameResult[]

  @@unique([position, roundId])
}

model TournamentMatch {
  id                       String                       @id @default(uuid())
  roundId                  String
  position                 Int
  // for SE/DE destination based on the result - if no winner destination then winner has won the tournament, if no loser destination loser is eliminated
  winnerDestinationMatchId String?
  loserDestinationMatchId  String?
  winnerDestinationMatch   TournamentMatch?             @relation("winnerDestinationMatch", fields: [winnerDestinationMatchId], references: [id])
  loserDestinationMatch    TournamentMatch?             @relation("loserDestinationMatch", fields: [loserDestinationMatchId], references: [id])
  round                    TournamentRound              @relation(fields: [roundId], references: [id])
  participants             TournamentMatchParticipant[]
  results                  TournamentMatchGameResult[]
  winnerSourceMatches      TournamentMatch[]            @relation("winnerDestinationMatch")
  loserSourceMatches       TournamentMatch[]            @relation("loserDestinationMatch")
}

enum TeamOrder {
  UPPER
  LOWER
}

model TournamentMatchParticipant {
  order   TeamOrder
  teamId  String
  matchId String
  team    TournamentTeam  @relation(fields: [teamId], references: [id])
  match   TournamentMatch @relation(fields: [matchId], references: [id])

  @@unique([teamId, matchId])
}

model TournamentMatchGameResult {
  id           String               @id @default(uuid())
  matchId      String
  roundStageId String
  // TODO: winnerTeamId instead
  winner       TeamOrder
  reporterId   String
  createdAt    DateTime             @default(now())
  match        TournamentMatch      @relation(fields: [matchId], references: [id])
  players      User[]
  roundStage   TournamentRoundStage @relation(fields: [roundStageId], references: [id])

  @@unique([matchId, roundStageId])
}

enum LfgGroupType {
  TWIN
  QUAD
  VERSUS
}

model LfgGroup {
  id            String               @id @default(uuid())
  ranked        Boolean?
  type          LfgGroupType
  active        Boolean              @default(true)
  looking       Boolean
  matchId       String?
  inviteCode    String               @default(uuid())
  createdAt     DateTime             @default(now())
  lastActionAt  DateTime             @default(now())
  members       LfgGroupMember[]
  match         LfgGroupMatch?       @relation(fields: [matchId], references: [id])
  likedGroups   LfgGroupLike[]       @relation("liker")
  likesReceived LfgGroupLike[]       @relation("target")
  matches       LfgGroupMatchStage[]

  @@index([active])
  @@index([looking])
  @@index([type])
}

model LfgGroupLike {
  likerId   String
  targetId  String
  liker     LfgGroup @relation("liker", fields: [likerId], references: [id], onDelete: Cascade)
  target    LfgGroup @relation("target", fields: [targetId], references: [id], onDelete: Cascade)
  createdAt DateTime @default(now())

  @@unique([likerId, targetId])
}

model LfgGroupMember {
  groupId  String
  memberId String
  captain  Boolean  @default(false)
  group    LfgGroup @relation(fields: [groupId], references: [id])
  user     User     @relation(fields: [memberId], references: [id])

  @@unique([groupId, memberId])
}

model LfgGroupMatch {
  id            String               @id @default(uuid())
  createdAt     DateTime             @default(now())
  groups        LfgGroup[]
  changedSkills Skill[]
  stages        LfgGroupMatchStage[]
}

model LfgGroupMatchStage {
  lfgGroupMatchId String
  stageId         Int
  order           Int
  winnerGroupId   String?
  lfgGroupMatch   LfgGroupMatch @relation(fields: [lfgGroupMatchId], references: [id])
  stage           Stage         @relation(fields: [stageId], references: [id])
  winnerGroup     LfgGroup?     @relation(fields: [winnerGroupId], references: [id])

  @@unique([lfgGroupMatchId, order])
}

model Skill {
  id           String         @id @default(uuid())
  userId       String
  mu           Float
  sigma        Float
  matchId      String?
  tournamentId String?
  createdAt    DateTime       @default(now())
  user         User           @relation(fields: [userId], references: [id])
  match        LfgGroupMatch? @relation(fields: [matchId], references: [id])
  tournament   Tournament?    @relation(fields: [tournamentId], references: [id])

  // One event can only count for skill once
  @@unique([userId, matchId])
  @@unique([userId, tournamentId])
}
