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

generator zod {
  provider = "zod-prisma-types"
  output   = "../src/generated/zod"
}

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

enum Role {
  ADMIN
  GUEST
}

model User {
  id            String          @id @default(cuid())
  name          String?
  email         String?         @unique
  password      String?
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
  // Optional for WebAuthn support
  Authenticator Authenticator[]

  role        Role         @default(GUEST)
  problems    Problem[]
  submissions Submission[]

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

enum Difficulty {
  EASY
  MEDIUM
  HARD
}

model Problem {
  id           String               @id @default(cuid())
  displayId    Int                  @unique
  titles       ProblemTitle[]
  descriptions ProblemDescription[]
  solutions    ProblemSolution[]
  difficulty   Difficulty           @default(EASY)
  published    Boolean              @default(false)
  userId       String
  user         User                 @relation(fields: [userId], references: [id], onDelete: Cascade)
  timeLimit    Int                  @default(1000)
  memoryLimit  Int                  @default(128)
  templates    Template[]
  testcases    Testcase[]
  submissions  Submission[]

  @@index([userId])
  @@index([difficulty])
}

enum Language {
  en
  zh
}

model ProblemTitle {
  id        String   @id @default(cuid())
  language  Language
  content   String
  problemId String
  problem   Problem  @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@unique([problemId, language])
}

model ProblemDescription {
  id        String   @id @default(cuid())
  language  Language
  content   String
  problemId String
  problem   Problem  @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@unique([problemId, language])
}

model ProblemSolution {
  id        String   @id @default(cuid())
  language  Language
  content   String
  problemId String
  problem   Problem  @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@unique([problemId, language])
}

enum EditorLanguage {
  c
  cpp
}

model EditorLanguageConfig {
  language             EditorLanguage        @unique
  label                String
  fileName             String
  fileExtension        String
  languageServerConfig LanguageServerConfig? @relation
  dockerConfig         DockerConfig?         @relation
}

enum LanguageServerProtocol {
  ws
  wss
}

model LanguageServerConfig {
  language             EditorLanguage         @unique
  protocol             LanguageServerProtocol
  hostname             String
  port                 Int?
  path                 String?
  editorLanguageConfig EditorLanguageConfig   @relation(fields: [language], references: [language])
}

model DockerConfig {
  language             EditorLanguage       @unique
  image                String
  tag                  String
  workingDir           String
  compileOutputLimit   Int
  runOutputLimit       Int
  editorLanguageConfig EditorLanguageConfig @relation(fields: [language], references: [language])
}

model Template {
  language  EditorLanguage
  template  String
  problemId String
  problem   Problem        @relation(fields: [problemId], references: [id], onDelete: Cascade)

  @@id([problemId, language])
}

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
}

model Submission {
  id            String         @id @default(cuid())
  language      EditorLanguage
  code          String
  status        Status
  message       String?
  executionTime Int?
  memoryUsage   Int?

  userId    String
  problemId String

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

  testcaseResults TestcaseResult[]

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

model Testcase {
  id              String           @id @default(cuid())
  problemId       String
  problem         Problem          @relation(fields: [problemId], references: [id], onDelete: Cascade)
  data            TestcaseData[]
  expectedOutput  String
  testcaseResults TestcaseResult[]
}

model TestcaseData {
  id         String   @id @default(cuid())
  index      Int
  label      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

  executionTime 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 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?

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

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

  @@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])
}
