// =============================================================================
// MOPC Platform - Prisma Schema
// =============================================================================
// This schema defines the database structure for the Monaco Ocean Protection
// Challenge jury voting platform.

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "windows", "linux-musl-openssl-3.0.x"]
}

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

// =============================================================================
// ENUMS
// =============================================================================

enum UserRole {
  SUPER_ADMIN
  PROGRAM_ADMIN
  JURY_MEMBER
  MENTOR
  OBSERVER
  APPLICANT
}

enum UserStatus {
  INVITED
  ACTIVE
  SUSPENDED
}

enum ProgramStatus {
  DRAFT
  ACTIVE
  ARCHIVED
}

enum RoundStatus {
  DRAFT
  ACTIVE
  CLOSED
  ARCHIVED
}

enum ProjectStatus {
  SUBMITTED
  ELIGIBLE
  ASSIGNED
  SEMIFINALIST
  FINALIST
  REJECTED
}

enum EvaluationStatus {
  NOT_STARTED
  DRAFT
  SUBMITTED
  LOCKED
}

enum AssignmentMethod {
  MANUAL
  BULK
  AI_SUGGESTED
  AI_AUTO
  ALGORITHM
}

enum FileType {
  EXEC_SUMMARY
  PRESENTATION
  VIDEO
  OTHER
  BUSINESS_PLAN
  VIDEO_PITCH
  SUPPORTING_DOC
}

enum SubmissionSource {
  MANUAL
  CSV
  NOTION
  TYPEFORM
  PUBLIC_FORM
}

enum RoundType {
  FILTERING
  EVALUATION
  LIVE_EVENT
}

enum SettingType {
  STRING
  NUMBER
  BOOLEAN
  JSON
  SECRET
}

enum SettingCategory {
  AI
  BRANDING
  EMAIL
  STORAGE
  SECURITY
  DEFAULTS
  WHATSAPP
}

enum NotificationChannel {
  EMAIL
  WHATSAPP
  BOTH
  NONE
}

enum ResourceType {
  PDF
  VIDEO
  DOCUMENT
  LINK
  OTHER
}

enum CohortLevel {
  ALL
  SEMIFINALIST
  FINALIST
}

enum PartnerVisibility {
  ADMIN_ONLY
  JURY_VISIBLE
  PUBLIC
}

enum PartnerType {
  SPONSOR
  PARTNER
  SUPPORTER
  MEDIA
  OTHER
}

enum FormFieldType {
  TEXT
  TEXTAREA
  NUMBER
  EMAIL
  PHONE
  URL
  DATE
  DATETIME
  SELECT
  MULTI_SELECT
  RADIO
  CHECKBOX
  CHECKBOX_GROUP
  FILE
  FILE_MULTIPLE
  SECTION
  INSTRUCTIONS
}

enum SpecialFieldType {
  TEAM_MEMBERS          // Team member repeater
  COMPETITION_CATEGORY  // Business Concept vs Startup
  OCEAN_ISSUE           // Ocean issue dropdown
  FILE_UPLOAD           // File upload
  GDPR_CONSENT          // GDPR consent checkbox
  COUNTRY_SELECT        // Country dropdown
}

// =============================================================================
// APPLICANT SYSTEM ENUMS
// =============================================================================

enum CompetitionCategory {
  STARTUP           // Existing companies
  BUSINESS_CONCEPT  // Students/graduates
}

enum OceanIssue {
  POLLUTION_REDUCTION
  CLIMATE_MITIGATION
  TECHNOLOGY_INNOVATION
  SUSTAINABLE_SHIPPING
  BLUE_CARBON
  HABITAT_RESTORATION
  COMMUNITY_CAPACITY
  SUSTAINABLE_FISHING
  CONSUMER_AWARENESS
  OCEAN_ACIDIFICATION
  OTHER
}

enum TeamMemberRole {
  LEAD              // Primary contact / team lead
  MEMBER            // Regular team member
  ADVISOR           // Advisor/mentor from team side
}

enum MentorAssignmentMethod {
  MANUAL
  AI_SUGGESTED
  AI_AUTO
  ALGORITHM
}

// =============================================================================
// USERS & AUTHENTICATION
// =============================================================================

model User {
  id            String       @id @default(cuid())
  email         String       @unique
  name          String?
  emailVerified DateTime?    // Required by NextAuth Prisma adapter
  role          UserRole     @default(JURY_MEMBER)
  status        UserStatus   @default(INVITED)
  expertiseTags String[]     @default([])
  maxAssignments Int?        // Per-round limit
  metadataJson  Json?        @db.JsonB

  // Profile image
  profileImageKey      String?    // Storage key (e.g., "avatars/user123/1234567890.jpg")
  profileImageProvider String?    // Storage provider used: 's3' or 'local'

  // Phone and notification preferences (Phase 2)
  phoneNumber              String?
  phoneNumberVerified      Boolean              @default(false)
  notificationPreference   NotificationChannel  @default(EMAIL)
  whatsappOptIn            Boolean              @default(false)

  // Onboarding (Phase 2B)
  onboardingCompletedAt    DateTime?

  // Password authentication (hybrid auth)
  passwordHash             String?   // bcrypt hashed password
  passwordSetAt            DateTime? // When password was set
  mustSetPassword          Boolean   @default(true) // Force setup on first login

  // Invitation token for one-click invite acceptance
  inviteToken              String?   @unique
  inviteTokenExpiresAt     DateTime?

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

  // Relations
  assignments    Assignment[]
  auditLogs      AuditLog[]
  gracePeriods   GracePeriod[]
  grantedGracePeriods GracePeriod[] @relation("GrantedBy")
  notificationLogs NotificationLog[]
  createdResources LearningResource[] @relation("ResourceCreatedBy")
  resourceAccess   ResourceAccess[]
  submittedProjects Project[] @relation("ProjectSubmittedBy")
  liveVotes        LiveVote[]

  // Team membership & mentorship
  teamMemberships   TeamMember[]
  mentorAssignments MentorAssignment[] @relation("MentorAssignments")

  // Awards
  awardJurorships   AwardJuror[]
  awardVotes        AwardVote[]

  // Filtering overrides
  filteringOverrides FilteringResult[] @relation("FilteringOverriddenBy")

  // Award overrides
  awardEligibilityOverrides AwardEligibility[] @relation("AwardEligibilityOverriddenBy")

  // In-app notifications
  notifications            InAppNotification[] @relation("UserNotifications")
  notificationSettingsUpdated NotificationEmailSetting[] @relation("NotificationSettingUpdater")

  // NextAuth relations
  accounts       Account[]
  sessions       Session[]

  @@index([email])
  @@index([role])
  @@index([status])
}

// NextAuth.js required models
model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

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

  @@unique([provider, providerAccountId])
  @@index([userId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime

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

  @@index([userId])
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

// =============================================================================
// PROGRAMS & ROUNDS
// =============================================================================

model Program {
  id           String        @id @default(cuid())
  name         String        // e.g., "Monaco Ocean Protection Challenge"
  year         Int           // e.g., 2026
  status       ProgramStatus @default(DRAFT)
  description  String?
  settingsJson Json?         @db.JsonB

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

  // Relations
  rounds            Round[]
  projects          Project[]
  learningResources LearningResource[]
  partners          Partner[]
  applicationForms  ApplicationForm[]
  specialAwards     SpecialAward[]

  @@unique([name, year])
  @@index([status])
}

model Round {
  id              String      @id @default(cuid())
  programId       String
  name            String      // e.g., "Round 1 - Semi-Finalists"
  slug            String?     @unique // URL-friendly identifier for public submissions
  status          RoundStatus @default(DRAFT)
  roundType       RoundType   @default(EVALUATION)
  sortOrder       Int         @default(0)  // Progression order within program

  // Submission window (for applicant portal)
  submissionDeadline DateTime? // Deadline for project submissions
  submissionStartDate  DateTime?  // When submissions open
  submissionEndDate    DateTime?  // When submissions close (replaces submissionDeadline if set)
  lateSubmissionGrace  Int?       // Hours of grace period after deadline

  // Phase-specific deadlines
  phase1Deadline       DateTime?
  phase2Deadline       DateTime?

  // Voting window
  votingStartAt   DateTime?
  votingEndAt     DateTime?

  // Configuration
  requiredReviews Int         @default(3) // Min evaluations per project
  settingsJson    Json?       @db.JsonB   // Grace periods, visibility rules, etc.

  // Notification sent to project team when they enter this round
  entryNotificationType String?  // e.g., "ADVANCED_SEMIFINAL", "ADVANCED_FINAL"

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

  // Relations
  program           Program          @relation(fields: [programId], references: [id], onDelete: Cascade)
  roundProjects     RoundProject[]
  assignments       Assignment[]
  evaluationForms   EvaluationForm[]
  gracePeriods      GracePeriod[]
  liveVotingSession LiveVotingSession?
  filteringRules    FilteringRule[]
  filteringResults  FilteringResult[]
  filteringJobs     FilteringJob[]
  applicationForm   ApplicationForm?

  @@index([programId])
  @@index([status])
  @@index([roundType])
  @@index([votingStartAt, votingEndAt])
  @@index([submissionStartDate, submissionEndDate])
}

model EvaluationForm {
  id           String  @id @default(cuid())
  roundId      String
  version      Int     @default(1)

  // Form configuration
  // criteriaJson: Array of { id, label, description, scale, weight, required }
  criteriaJson Json    @db.JsonB
  // scalesJson: { "1-5": { min, max, labels }, "1-10": { min, max, labels } }
  scalesJson   Json?   @db.JsonB
  isActive     Boolean @default(false)

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

  // Relations
  round       Round        @relation(fields: [roundId], references: [id], onDelete: Cascade)
  evaluations Evaluation[]

  @@unique([roundId, version])
  @@index([roundId, isActive])
}

// =============================================================================
// PROJECTS
// =============================================================================

model Project {
  id              String           @id @default(cuid())
  programId       String

  // Core fields
  title           String
  teamName        String?
  description     String?          @db.Text

  // Competition category
  competitionCategory CompetitionCategory?
  oceanIssue          OceanIssue?

  // Location
  country         String?
  geographicZone  String?          // "Europe, France"

  // Institution (for students/Business Concepts)
  institution     String?

  // Mentorship
  wantsMentorship Boolean          @default(false)

  // Founding date
  foundedAt       DateTime?        // When the project/company was founded

  // Submission links (external, from CSV)
  phase1SubmissionUrl String?
  phase2SubmissionUrl String?

  // Referral tracking
  referralSource  String?

  // Internal admin fields
  internalComments String?         @db.Text
  applicationStatus String?        // "Received", etc.

  // Submission tracking
  submissionSource   SubmissionSource @default(MANUAL)
  submittedByEmail   String?
  submittedAt        DateTime?
  submittedByUserId  String?

  // Project branding
  logoKey         String?       // Storage key (e.g., "logos/project456/1234567890.png")
  logoProvider    String?       // Storage provider used: 's3' or 'local'

  // Flexible fields
  tags            String[]      @default([]) // "Ocean Conservation", "Tech", etc.
  metadataJson    Json?         @db.JsonB    // Custom fields from Typeform, etc.
  externalIdsJson Json?         @db.JsonB    // Typeform ID, Notion ID, etc.

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

  // Relations
  program          Program            @relation(fields: [programId], references: [id], onDelete: Cascade)
  roundProjects    RoundProject[]
  files            ProjectFile[]
  assignments      Assignment[]
  submittedBy      User?              @relation("ProjectSubmittedBy", fields: [submittedByUserId], references: [id], onDelete: SetNull)
  teamMembers      TeamMember[]
  mentorAssignment MentorAssignment?
  filteringResults FilteringResult[]
  awardEligibilities AwardEligibility[]
  awardVotes         AwardVote[]
  wonAwards          SpecialAward[]   @relation("AwardWinner")

  @@index([programId])
  @@index([tags])
  @@index([submissionSource])
  @@index([submittedByUserId])
  @@index([competitionCategory])
  @@index([oceanIssue])
  @@index([country])
}

model RoundProject {
  id         String        @id @default(cuid())
  roundId    String
  projectId  String
  status     ProjectStatus @default(SUBMITTED)
  addedAt    DateTime      @default(now())

  // Relations
  round      Round         @relation(fields: [roundId], references: [id], onDelete: Cascade)
  project    Project       @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@unique([roundId, projectId])
  @@index([roundId])
  @@index([projectId])
  @@index([status])
}

model ProjectFile {
  id        String   @id @default(cuid())
  projectId String

  // File info
  fileType  FileType
  fileName  String
  mimeType  String
  size      Int      // bytes

  // MinIO location
  bucket    String
  objectKey String

  createdAt DateTime @default(now())

  // Relations
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@unique([bucket, objectKey])
  @@index([projectId])
  @@index([fileType])
}

// =============================================================================
// ASSIGNMENTS & EVALUATIONS
// =============================================================================

model Assignment {
  id               String           @id @default(cuid())
  userId           String
  projectId        String
  roundId          String

  // Assignment info
  method           AssignmentMethod @default(MANUAL)
  isRequired       Boolean          @default(true)
  isCompleted      Boolean          @default(false)

  // AI assignment metadata
  aiConfidenceScore  Float?         // 0-1 confidence from AI
  expertiseMatchScore Float?        // 0-1 match score
  aiReasoning        String?        @db.Text

  createdAt DateTime @default(now())
  createdBy String?  // Admin who created the assignment

  // Relations
  user       User        @relation(fields: [userId], references: [id], onDelete: Cascade)
  project    Project     @relation(fields: [projectId], references: [id], onDelete: Cascade)
  round      Round       @relation(fields: [roundId], references: [id], onDelete: Cascade)
  evaluation Evaluation?

  @@unique([userId, projectId, roundId])
  @@index([userId])
  @@index([projectId])
  @@index([roundId])
  @@index([isCompleted])
}

model Evaluation {
  id                  String           @id @default(cuid())
  assignmentId        String           @unique
  formId              String

  // Status
  status              EvaluationStatus @default(NOT_STARTED)

  // Scores
  // criterionScoresJson: { "criterion_id": score, ... }
  criterionScoresJson Json?            @db.JsonB
  globalScore         Int?             // 1-10
  binaryDecision      Boolean?         // Yes/No for semi-finalist
  feedbackText        String?          @db.Text

  // Versioning
  version             Int              @default(1)

  // Timestamps
  createdAt  DateTime  @default(now())
  updatedAt  DateTime  @updatedAt
  submittedAt DateTime?

  // Relations
  assignment Assignment     @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
  form       EvaluationForm @relation(fields: [formId], references: [id])

  @@index([status])
  @@index([submittedAt])
  @@index([formId])
}

// =============================================================================
// GRACE PERIODS
// =============================================================================

model GracePeriod {
  id            String   @id @default(cuid())
  roundId       String
  userId        String
  projectId     String?  // Optional: specific project or all projects in round

  extendedUntil DateTime
  reason        String?  @db.Text
  grantedById   String

  createdAt DateTime @default(now())

  // Relations
  round     Round   @relation(fields: [roundId], references: [id], onDelete: Cascade)
  user      User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  grantedBy User    @relation("GrantedBy", fields: [grantedById], references: [id])

  @@index([roundId])
  @@index([userId])
  @@index([extendedUntil])
  @@index([grantedById])
  @@index([projectId])
}

// =============================================================================
// SYSTEM SETTINGS
// =============================================================================

model SystemSettings {
  id          String          @id @default(cuid())
  key         String          @unique
  value       String          @db.Text
  type        SettingType     @default(STRING)
  category    SettingCategory

  description String?
  isSecret    Boolean         @default(false) // If true, value is encrypted

  updatedAt   DateTime        @updatedAt
  updatedBy   String?

  @@index([category])
}

// =============================================================================
// AUDIT LOGGING
// =============================================================================

model AuditLog {
  id          String   @id @default(cuid())
  userId      String?

  // Event info
  action      String   // "CREATE", "UPDATE", "DELETE", "LOGIN", "EXPORT", etc.
  entityType  String   // "Round", "Project", "Evaluation", etc.
  entityId    String?

  // Details
  detailsJson Json?    @db.JsonB // Before/after values, additional context

  // Request info
  ipAddress   String?
  userAgent   String?

  timestamp   DateTime @default(now())

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

  @@index([userId])
  @@index([action])
  @@index([entityType, entityId])
  @@index([timestamp])
}

// =============================================================================
// AI USAGE TRACKING
// =============================================================================

model AIUsageLog {
  id               String   @id @default(cuid())
  createdAt        DateTime @default(now())

  // Who/what triggered it
  userId           String?
  action           String   // ASSIGNMENT, FILTERING, AWARD_ELIGIBILITY, MENTOR_MATCHING
  entityType       String?  // Round, Project, Award
  entityId         String?

  // What was used
  model            String   // gpt-4o, gpt-4o-mini, o1, etc.
  promptTokens     Int
  completionTokens Int
  totalTokens      Int

  // Cost tracking
  estimatedCostUsd Decimal? @db.Decimal(10, 6)

  // Request context
  batchSize        Int?
  itemsProcessed   Int?

  // Status
  status           String   // SUCCESS, PARTIAL, ERROR
  errorMessage     String?

  // Detailed data (optional)
  detailsJson      Json?    @db.JsonB

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

// =============================================================================
// NOTIFICATION LOG (Phase 2)
// =============================================================================

model NotificationLog {
  id          String              @id @default(cuid())
  userId      String
  channel     NotificationChannel
  provider    String?             // META, TWILIO, SMTP
  type        String              // MAGIC_LINK, REMINDER, ANNOUNCEMENT, JURY_INVITATION
  status      String              // PENDING, SENT, DELIVERED, FAILED
  externalId  String?             // Message ID from provider
  errorMsg    String?             @db.Text

  createdAt   DateTime            @default(now())

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

  @@index([userId])
  @@index([status])
  @@index([createdAt])
}

// =============================================================================
// IN-APP NOTIFICATIONS
// =============================================================================

model InAppNotification {
  id          String    @id @default(cuid())
  userId      String
  type        String    // FILTERING_COMPLETE, NEW_APPLICATION, ASSIGNED_TO_PROJECT, etc.
  priority    String    @default("normal") // low, normal, high, urgent
  icon        String?   // lucide icon name
  title       String
  message     String    @db.Text
  linkUrl     String?   // Where to navigate when clicked
  linkLabel   String?   // CTA text
  metadata    Json?     @db.JsonB  // Extra context (projectId, roundId, etc.)
  groupKey    String?   // For batching similar notifications

  isRead      Boolean   @default(false)
  readAt      DateTime?
  expiresAt   DateTime? // Auto-dismiss after date

  createdAt   DateTime  @default(now())

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

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

model NotificationEmailSetting {
  id                String   @id @default(cuid())
  notificationType  String   @unique  // e.g., "ADVANCED_TO_ROUND", "ASSIGNED_TO_PROJECT"
  category          String   // "team", "jury", "mentor", "admin"
  label             String   // Human-readable label for admin UI
  description       String?  // Help text
  sendEmail         Boolean  @default(true)
  emailSubject      String?  // Custom subject template (optional)
  emailTemplate     String?  @db.Text  // Custom body template (optional)

  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  updatedById       String?
  updatedBy         User?    @relation("NotificationSettingUpdater", fields: [updatedById], references: [id])

  @@index([category])
}

// =============================================================================
// LEARNING HUB (Phase 2)
// =============================================================================

model LearningResource {
  id            String        @id @default(cuid())
  programId     String?       // null = global resource
  title         String
  description   String?       @db.Text
  contentJson   Json?         @db.JsonB  // BlockNote document structure
  resourceType  ResourceType
  cohortLevel   CohortLevel   @default(ALL)

  // File storage (for uploaded resources)
  fileName      String?
  mimeType      String?
  size          Int?
  bucket        String?
  objectKey     String?

  // External link
  externalUrl   String?

  sortOrder     Int           @default(0)
  isPublished   Boolean       @default(false)

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

  // Relations
  program       Program?         @relation(fields: [programId], references: [id], onDelete: SetNull)
  createdBy     User             @relation("ResourceCreatedBy", fields: [createdById], references: [id])
  accessLogs    ResourceAccess[]

  @@index([programId])
  @@index([cohortLevel])
  @@index([isPublished])
  @@index([sortOrder])
}

model ResourceAccess {
  id          String   @id @default(cuid())
  resourceId  String
  userId      String
  accessedAt  DateTime @default(now())
  ipAddress   String?

  // Relations
  resource    LearningResource @relation(fields: [resourceId], references: [id], onDelete: Cascade)
  user        User             @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([resourceId])
  @@index([userId])
  @@index([accessedAt])
}

// =============================================================================
// PARTNER MANAGEMENT (Phase 2)
// =============================================================================

model Partner {
  id            String            @id @default(cuid())
  programId     String?           // null = global partner
  name          String
  description   String?           @db.Text
  website       String?
  partnerType   PartnerType       @default(PARTNER)
  visibility    PartnerVisibility @default(ADMIN_ONLY)

  // Logo file
  logoFileName  String?
  logoBucket    String?
  logoObjectKey String?

  sortOrder     Int               @default(0)
  isActive      Boolean           @default(true)

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

  // Relations
  program       Program?          @relation(fields: [programId], references: [id], onDelete: SetNull)

  @@index([programId])
  @@index([partnerType])
  @@index([visibility])
  @@index([isActive])
  @@index([sortOrder])
}

// =============================================================================
// APPLICATION FORMS (Phase 2)
// =============================================================================

model ApplicationForm {
  id              String   @id @default(cuid())
  programId       String?  // null = global form
  name            String
  description     String?  @db.Text
  status          String   @default("DRAFT") // DRAFT, PUBLISHED, CLOSED

  isPublic        Boolean  @default(false)
  publicSlug      String?  @unique           // /apply/ocean-challenge-2026
  submissionLimit Int?
  opensAt         DateTime?
  closesAt        DateTime?

  confirmationMessage String? @db.Text

  // Round linking (for onboarding forms that create projects)
  roundId                  String?   @unique

  // Email settings
  sendConfirmationEmail    Boolean   @default(true)
  sendTeamInviteEmails     Boolean   @default(true)
  confirmationEmailSubject String?
  confirmationEmailBody    String?   @db.Text

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

  // Relations
  program         Program?                    @relation(fields: [programId], references: [id], onDelete: SetNull)
  round           Round?                      @relation(fields: [roundId], references: [id], onDelete: SetNull)
  fields          ApplicationFormField[]
  steps           OnboardingStep[]
  submissions     ApplicationFormSubmission[]

  @@index([programId])
  @@index([status])
  @@index([isPublic])
  @@index([roundId])
}

model ApplicationFormField {
  id          String        @id @default(cuid())
  formId      String
  stepId      String?       // Which step this field belongs to (for onboarding)
  fieldType   FormFieldType
  name        String        // Internal name (e.g., "project_title")
  label       String        // Display label (e.g., "Project Title")
  description String?       @db.Text
  placeholder String?

  required    Boolean       @default(false)
  minLength   Int?
  maxLength   Int?
  minValue    Float?        // For NUMBER type
  maxValue    Float?        // For NUMBER type

  optionsJson   Json?       @db.JsonB  // For select/radio: [{ value, label }]
  conditionJson Json?       @db.JsonB  // Conditional logic: { fieldId, operator, value }

  // Onboarding-specific fields
  projectMapping String?                 // Maps to Project column: "title", "description", etc.
  specialType    SpecialFieldType?       // Special handling for complex fields

  sortOrder   Int           @default(0)
  width       String        @default("full")  // full, half

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

  // Relations
  form        ApplicationForm  @relation(fields: [formId], references: [id], onDelete: Cascade)
  step        OnboardingStep?  @relation(fields: [stepId], references: [id], onDelete: SetNull)

  @@index([formId])
  @@index([stepId])
  @@index([sortOrder])
}

model OnboardingStep {
  id            String   @id @default(cuid())
  formId        String
  name          String           // Internal identifier (e.g., "category", "contact")
  title         String           // Display title (e.g., "Category", "Contact Information")
  description   String?          @db.Text
  sortOrder     Int              @default(0)
  isOptional    Boolean          @default(false)
  conditionJson Json?            @db.JsonB  // Conditional visibility: { fieldId, operator, value }

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

  // Relations
  form          ApplicationForm  @relation(fields: [formId], references: [id], onDelete: Cascade)
  fields        ApplicationFormField[]

  @@index([formId])
  @@index([sortOrder])
}

model ApplicationFormSubmission {
  id          String   @id @default(cuid())
  formId      String
  email       String?
  name        String?
  dataJson    Json     @db.JsonB  // Field values: { fieldName: value, ... }
  status      String   @default("SUBMITTED") // SUBMITTED, REVIEWED, APPROVED, REJECTED

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

  // Relations
  form        ApplicationForm  @relation(fields: [formId], references: [id], onDelete: Cascade)
  files       SubmissionFile[]

  @@index([formId])
  @@index([status])
  @@index([email])
  @@index([createdAt])
}

model SubmissionFile {
  id           String @id @default(cuid())
  submissionId String
  fieldName    String
  fileName     String
  mimeType     String?
  size         Int?
  bucket       String
  objectKey    String

  createdAt    DateTime @default(now())

  // Relations
  submission   ApplicationFormSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)

  @@index([submissionId])
  @@unique([bucket, objectKey])
}

// =============================================================================
// EXPERTISE TAGS (Phase 2B)
// =============================================================================

model ExpertiseTag {
  id          String   @id @default(cuid())
  name        String   @unique
  description String?
  category    String?  // "Marine Science", "Technology", "Policy"
  color       String?  // Hex for badge
  isActive    Boolean  @default(true)
  sortOrder   Int      @default(0)

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

  @@index([category])
  @@index([isActive])
  @@index([sortOrder])
}

// =============================================================================
// LIVE VOTING (Phase 2B)
// =============================================================================

model LiveVotingSession {
  id                   String    @id @default(cuid())
  roundId              String    @unique
  status               String    @default("NOT_STARTED") // NOT_STARTED, IN_PROGRESS, PAUSED, COMPLETED
  currentProjectIndex  Int       @default(0)
  currentProjectId     String?
  votingStartedAt      DateTime?
  votingEndsAt         DateTime?
  projectOrderJson     Json?     @db.JsonB  // Array of project IDs in presentation order

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

  // Relations
  round                Round     @relation(fields: [roundId], references: [id], onDelete: Cascade)
  votes                LiveVote[]

  @@index([status])
}

model LiveVote {
  id         String   @id @default(cuid())
  sessionId  String
  projectId  String
  userId     String
  score      Int      // 1-10
  votedAt    DateTime @default(now())

  // Relations
  session    LiveVotingSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
  user       User              @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([sessionId, projectId, userId])
  @@index([sessionId])
  @@index([projectId])
  @@index([userId])
}

// =============================================================================
// TEAM MEMBERSHIP
// =============================================================================

model TeamMember {
  id        String         @id @default(cuid())
  projectId String
  userId    String
  role      TeamMemberRole @default(MEMBER)
  title     String?        // "CEO", "CTO", etc.
  joinedAt  DateTime       @default(now())

  // Relations
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
  user    User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([projectId, userId])
  @@index([projectId])
  @@index([userId])
  @@index([role])
}

// =============================================================================
// MENTOR ASSIGNMENT
// =============================================================================

model MentorAssignment {
  id        String   @id @default(cuid())
  projectId String   @unique  // One mentor per project
  mentorId  String             // User with MENTOR role or expertise

  // Assignment tracking
  method            MentorAssignmentMethod @default(MANUAL)
  assignedAt        DateTime               @default(now())
  assignedBy        String?                // Admin who assigned

  // AI assignment metadata
  aiConfidenceScore   Float?
  expertiseMatchScore Float?
  aiReasoning         String?  @db.Text

  // Relations
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
  mentor  User    @relation("MentorAssignments", fields: [mentorId], references: [id])

  @@index([mentorId])
  @@index([method])
}

// =============================================================================
// FILTERING ROUND SYSTEM
// =============================================================================

enum FilteringOutcome {
  PASSED
  FILTERED_OUT
  FLAGGED
}

enum FilteringRuleType {
  FIELD_BASED
  DOCUMENT_CHECK
  AI_SCREENING
}

model FilteringRule {
  id         String            @id @default(cuid())
  roundId    String
  name       String
  ruleType   FilteringRuleType
  configJson Json              @db.JsonB  // Conditions, logic, action per rule type
  priority   Int               @default(0)
  isActive   Boolean           @default(true)

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

  // Relations
  round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)

  @@index([roundId])
  @@index([priority])
}

model FilteringResult {
  id               String           @id @default(cuid())
  roundId          String
  projectId        String
  outcome          FilteringOutcome
  ruleResultsJson  Json?            @db.JsonB  // Per-rule results
  aiScreeningJson  Json?            @db.JsonB  // AI screening details

  // Admin override
  overriddenBy     String?
  overriddenAt     DateTime?
  overrideReason   String?          @db.Text
  finalOutcome     FilteringOutcome?

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

  // Relations
  round   Round   @relation(fields: [roundId], references: [id], onDelete: Cascade)
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
  overriddenByUser User? @relation("FilteringOverriddenBy", fields: [overriddenBy], references: [id], onDelete: SetNull)

  @@unique([roundId, projectId])
  @@index([roundId])
  @@index([projectId])
  @@index([outcome])
}

// Tracks progress of long-running filtering jobs
model FilteringJob {
  id              String            @id @default(cuid())
  roundId         String
  status          FilteringJobStatus @default(PENDING)
  totalProjects   Int               @default(0)
  totalBatches    Int               @default(0)
  currentBatch    Int               @default(0)
  processedCount  Int               @default(0)
  passedCount     Int               @default(0)
  filteredCount   Int               @default(0)
  flaggedCount    Int               @default(0)
  errorMessage    String?           @db.Text
  startedAt       DateTime?
  completedAt     DateTime?

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

  // Relations
  round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)

  @@index([roundId])
  @@index([status])
}

enum FilteringJobStatus {
  PENDING
  RUNNING
  COMPLETED
  FAILED
}

// =============================================================================
// SPECIAL AWARDS SYSTEM
// =============================================================================

enum AwardScoringMode {
  PICK_WINNER
  RANKED
  SCORED
}

enum AwardStatus {
  DRAFT
  NOMINATIONS_OPEN
  VOTING_OPEN
  CLOSED
  ARCHIVED
}

enum EligibilityMethod {
  AUTO
  MANUAL
}

model SpecialAward {
  id               String           @id @default(cuid())
  programId        String
  name             String
  description      String?          @db.Text
  status           AwardStatus      @default(DRAFT)

  // Criteria
  criteriaText       String?          @db.Text    // Plain-language criteria for AI
  autoTagRulesJson   Json?            @db.JsonB   // Deterministic eligibility rules
  useAiEligibility   Boolean          @default(true) // Whether AI evaluates eligibility

  // Scoring
  scoringMode      AwardScoringMode @default(PICK_WINNER)
  maxRankedPicks   Int?             // For RANKED mode

  // Voting window
  votingStartAt    DateTime?
  votingEndAt      DateTime?

  // Evaluation form (for SCORED mode)
  evaluationFormId String?

  // Winner
  winnerProjectId     String?
  winnerOverridden    Boolean          @default(false)
  winnerOverriddenBy  String?

  sortOrder        Int              @default(0)

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

  // Relations
  program          Program          @relation(fields: [programId], references: [id], onDelete: Cascade)
  winnerProject    Project?         @relation("AwardWinner", fields: [winnerProjectId], references: [id], onDelete: SetNull)
  eligibilities    AwardEligibility[]
  jurors           AwardJuror[]
  votes            AwardVote[]

  @@index([programId])
  @@index([status])
  @@index([sortOrder])
}

model AwardEligibility {
  id             String            @id @default(cuid())
  awardId        String
  projectId      String
  method         EligibilityMethod @default(AUTO)
  eligible       Boolean           @default(false)
  aiReasoningJson Json?            @db.JsonB

  // Admin override
  overriddenBy   String?
  overriddenAt   DateTime?

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

  // Relations
  award   SpecialAward @relation(fields: [awardId], references: [id], onDelete: Cascade)
  project Project      @relation(fields: [projectId], references: [id], onDelete: Cascade)
  overriddenByUser User? @relation("AwardEligibilityOverriddenBy", fields: [overriddenBy], references: [id], onDelete: SetNull)

  @@unique([awardId, projectId])
  @@index([awardId])
  @@index([projectId])
  @@index([eligible])
}

model AwardJuror {
  id      String @id @default(cuid())
  awardId String
  userId  String

  createdAt DateTime @default(now())

  // Relations
  award SpecialAward @relation(fields: [awardId], references: [id], onDelete: Cascade)
  user  User         @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([awardId, userId])
  @@index([awardId])
  @@index([userId])
}

model AwardVote {
  id        String   @id @default(cuid())
  awardId   String
  userId    String
  projectId String
  rank      Int?     // For RANKED mode
  votedAt   DateTime @default(now())

  // Relations
  award   SpecialAward @relation(fields: [awardId], references: [id], onDelete: Cascade)
  user    User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  project Project      @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@unique([awardId, userId, projectId])
  @@index([awardId])
  @@index([userId])
  @@index([projectId])
}
