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

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

enum Role {
  ADMIN
  GUEST
}

enum Difficulty {
  EASY
  MEDIUM
  HARD
}

enum Locale {
  en
  zh
}

enum Language {
  c
  cpp
}

enum Protocol {
  ws
  wss
}

enum Status {
  PD // PENDING
  QD // QUEUED
  CP // COMPILING
  CE // Compilation Error
  CS // Compilation Success
  RU // RUNNING
  TLE // Time Limit Exceeded
  MLE // Memory Limit Exceeded
  RE // Runtime Error
  AC // Accepted
  WA // Wrong Answer
  SE // System Error
}

enum ProblemContentType {
  TITLE
  DESCRIPTION
  SOLUTION
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String    @unique
  emailVerified DateTime?
  image         String?
  role          Role      @default(GUEST)

  accounts      Account[]
  sessions      Session[]
  // Optional for WebAuthn support
  Authenticator Authenticator[]
  problems      Problem[]
  submissions   Submission[]

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

model Problem {
  id          String     @id @default(cuid())
  displayId   Int        @unique
  difficulty  Difficulty @default(EASY)
  isPublished Boolean    @default(false)
  timeLimit   Int        @default(1000)
  memoryLimit Int        @default(134217728)

  localizations ProblemLocalization[]
  templates     Template[]
  testcases     Testcase[]
  submissions   Submission[]

  userId String?

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

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

model ProblemLocalization {
  problemId String
  locale    Locale
  type      ProblemContentType

  content String

  problem Problem @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@id([problemId, locale, type])
}

model Template {
  problemId String
  language  Language

  content String

  problem Problem @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@id([problemId, language])
}

model Submission {
  id          String   @id @default(cuid())
  language    Language
  content     String
  status      Status
  message     String?
  timeUsage   Int?
  memoryUsage Int?

  testcaseResults TestcaseResult[]

  userId    String
  problemId String

  user    User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  problem Problem @relation(fields: [problemId], references: [id], onDelete: Cascade)

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

model Testcase {
  id             String @id @default(cuid())
  expectedOutput String

  inputs          TestcaseInput[]
  testcaseResults TestcaseResult[]

  problemId String

  problem Problem @relation(fields: [problemId], references: [id], onDelete: Cascade)

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

model TestcaseInput {
  id    String @id @default(cuid())
  index Int
  name  String
  value String

  testcaseId String

  testcase Testcase @relation(fields: [testcaseId], references: [id], onDelete: Cascade)
}

model TestcaseResult {
  id          String  @id @default(cuid())
  isCorrect   Boolean
  output      String
  timeUsage   Int?
  memoryUsage Int?

  submissionId String
  testcaseId   String

  submission Submission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
  testcase   Testcase   @relation(fields: [testcaseId], references: [id], onDelete: Cascade)

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

model DockerConfig {
  language           Language @id
  image              String
  tag                String
  workingDir         String
  compileOutputLimit Int      @default(1048576)
  runOutputLimit     Int      @default(1048576)
}

model LanguageServerConfig {
  language Language @id
  protocol Protocol
  hostname String
  port     Int?
  path     String?
}

model Account {
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String?
  access_token      String?
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String?
  session_state     String?

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

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

  @@id([provider, providerAccountId])
}

model Session {
  sessionToken String   @unique
  userId       String
  expires      DateTime

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

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

model VerificationToken {
  identifier String
  token      String
  expires    DateTime

  @@id([identifier, token])
}

// Optional for WebAuthn support
model Authenticator {
  credentialID         String  @unique
  userId               String
  providerAccountId    String
  credentialPublicKey  String
  counter              Int
  credentialDeviceType String
  credentialBackedUp   Boolean
  transports           String?

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

  @@id([userId, credentialID])
}
