// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DATABASE_URL_UNPOOLED") // Direct connection for migrations (bypasses pooler)
}

/// Package table - stores NPM package metadata (package-level)
model Package {
  id String @id @default(cuid())

  // NPM Metadata
  npmPackageName String   @unique @map("npm_package_name") @db.VarChar(214)
  npmVersion     String   @map("npm_version") @db.VarChar(50)
  npmPublishedAt DateTime @map("npm_published_at")
  npmDescription String?  @map("npm_description") @db.Text
  npmRepository  Json?    @map("npm_repository") @db.JsonB
  npmHomepage    String?  @map("npm_homepage") @db.Text
  npmLicense     String?  @map("npm_license") @db.VarChar(50)
  npmKeywords    String[] @default([]) @map("npm_keywords") @db.Text
  npmReadme      String?  @map("npm_readme") @db.Text
  npmAuthor      Json?    @map("npm_author") @db.JsonB
  npmMaintainers Json?    @map("npm_maintainers") @db.JsonB

  // TPMJS Package-Level Metadata
  category       String   @db.VarChar(50)
  env            Json?    @db.JsonB // Environment variables (shared across tools)
  frameworks     String[] @default([]) @db.Text
  tier           String   @db.VarChar(20) // 'minimal' | 'rich'
  discoveryMethod String  @map("discovery_method") @db.VarChar(20) // 'keyword' | 'changes-feed'
  isOfficial     Boolean  @default(false) @map("is_official")

  // Package Metrics
  npmDownloadsLastMonth Int? @default(0) @map("npm_downloads_last_month")
  githubStars           Int? @default(0) @map("github_stars")

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  // Relations
  tools Tool[]

  @@index([category])
  @@index([isOfficial])
  @@index([npmDownloadsLastMonth])
  @@index([createdAt])
  @@map("packages")
}

/// Tool table - stores individual tools within packages
model Tool {
  id String @id @default(cuid())

  // Package Relation
  packageId String  @map("package_id")
  package   Package @relation(fields: [packageId], references: [id], onDelete: Cascade)

  // Tool Identity
  name String @db.VarChar(100) // e.g., "helloWorldTool", "default"

  // Tool Metadata
  description String @db.Text
  parameters  Json?  @db.JsonB // Legacy/fallback - author-provided parameters array
  returns     Json?  @db.JsonB // @deprecated - will be auto-extracted in future
  aiAgent     Json?  @map("ai_agent") @db.JsonB // @deprecated - will be auto-extracted in future

  // Schema Extraction Fields
  inputSchema                Json?     @map("input_schema") @db.JsonB // Full JSON Schema from executor
  schemaSource               String?   @map("schema_source") @db.VarChar(20) // 'extracted' | 'author' | null
  schemaExtractedAt          DateTime? @map("schema_extracted_at") // Only updated on successful extraction
  schemaExtractionAttemptAt  DateTime? @map("schema_extraction_attempt_at") // Updated on every attempt (for rate limiting)
  schemaExtractionError      String?   @map("schema_extraction_error") @db.Text // Error message from last failed attempt

  // Tool Discovery Fields
  toolDiscoverySource String? @map("tool_discovery_source") @db.VarChar(20) // 'auto' | 'manual' | null

  // Tool Metrics
  qualityScore Decimal? @map("quality_score") @db.Decimal(3, 2) // 0.00 to 1.00
  likeCount    Int      @default(0) @map("like_count")

  // Health Status Fields
  importHealth     HealthStatus? @default(UNKNOWN) @map("import_health")
  executionHealth  HealthStatus? @default(UNKNOWN) @map("execution_health")
  lastHealthCheck  DateTime?     @map("last_health_check")
  healthCheckError String?       @map("health_check_error") @db.Text

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  // View tracking (denormalized, rolled up daily)
  viewCount    Int      @default(0) @map("view_count")

  // Rating aggregates
  averageRating Decimal? @map("average_rating") @db.Decimal(2, 1) // 1.0 to 5.0
  ratingCount   Int      @default(0) @map("rating_count")
  reviewCount   Int      @default(0) @map("review_count")

  // Relations
  simulations     Simulation[]
  healthChecks    HealthCheck[]
  collections     CollectionTool[]
  agents          AgentTool[]
  likes           ToolLike[]
  ratings         ToolRating[]
  reviews         ToolReview[]
  skillsCache     ToolSkillsCache?
  skillQuestions  SkillQuestionTool[]

  @@unique([packageId, name])
  @@index([qualityScore])
  @@index([likeCount])
  @@index([averageRating])
  @@index([ratingCount])
  @@index([viewCount])
  @@index([reviewCount])
  @@index([importHealth])
  @@index([executionHealth])
  @@index([lastHealthCheck])
  @@map("tools")
}

/// Sync checkpoints - tracks progress of sync workers
model SyncCheckpoint {
  id String @id @default(cuid())

  source     String   @unique @db.VarChar(50) // 'changes-feed' | 'keyword-search' | 'metrics'
  checkpoint Json     @db.JsonB // Stores last sequence, timestamp, etc.
  updatedAt  DateTime @updatedAt @map("updated_at")

  @@map("sync_checkpoints")
}

/// Sync logs - audit trail of sync operations
model SyncLog {
  id String @id @default(cuid())

  source    String   @db.VarChar(50) // 'changes-feed' | 'keyword-search' | 'metrics'
  status    String   @db.VarChar(20) // 'success' | 'error' | 'partial'
  processed Int      @default(0) // Number of packages processed
  skipped   Int      @default(0) // Number of packages skipped
  errors    Int      @default(0) // Number of errors encountered
  message   String?  @db.Text // Error message or summary
  metadata  Json?    @db.JsonB // Additional context
  createdAt DateTime @default(now()) @map("created_at")

  @@index([source])
  @@index([status])
  @@index([createdAt])
  @@map("sync_logs")
}

/// Simulations - tracks tool playground executions
model Simulation {
  id String @id @default(cuid())

  // Relations
  toolId String @map("tool_id")
  tool   Tool   @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Request data
  userPrompt String  @map("user_prompt") @db.Text
  parameters Json?   @db.JsonB
  ipAddress  String? @map("ip_address") @db.VarChar(45)
  userAgent  String? @map("user_agent") @db.Text

  // Results
  status          String  @db.VarChar(20) // pending|running|success|error|timeout
  executionTimeMs Int?    @map("execution_time_ms")
  output          Json?   @db.JsonB
  error           String? @db.Text

  // AI metadata
  agentSteps Int     @default(0) @map("agent_steps")
  model      String? @db.VarChar(50)

  // Relations
  tokenUsage   TokenUsage?
  logs         ExecutionLog[]

  createdAt   DateTime  @default(now()) @map("created_at")
  completedAt DateTime? @map("completed_at")

  @@index([toolId])
  @@index([status])
  @@index([ipAddress, createdAt]) // For rate limiting
  @@map("simulations")
}

/// Token usage - tracks token consumption per simulation
model TokenUsage {
  id String @id @default(cuid())

  simulationId String     @unique @map("simulation_id")
  simulation   Simulation @relation(fields: [simulationId], references: [id], onDelete: Cascade)

  inputTokens    Int      @default(0) @map("input_tokens")
  toolDescTokens Int      @default(0) @map("tool_desc_tokens")
  schemaTokens   Int      @default(0) @map("schema_tokens")
  outputTokens   Int      @default(0) @map("output_tokens")
  totalTokens    Int      @default(0) @map("total_tokens")
  estimatedCost  Decimal? @map("estimated_cost") @db.Decimal(10, 6)

  createdAt DateTime @default(now()) @map("created_at")
  @@map("token_usage")
}

/// Execution logs - detailed logs for each simulation
model ExecutionLog {
  id String @id @default(cuid())

  simulationId String     @map("simulation_id")
  simulation   Simulation @relation(fields: [simulationId], references: [id], onDelete: Cascade)

  timestamp DateTime @default(now())
  level     String   @db.VarChar(20) // info|warning|error|debug
  event     String   @db.VarChar(50)
  message   String   @db.Text
  metadata  Json?    @db.JsonB

  @@index([simulationId])
  @@map("execution_logs")
}

/// HealthCheck table - tracks full audit history of health checks
model HealthCheck {
  id String @id @default(cuid())

  // Relations
  toolId String @map("tool_id")
  tool   Tool   @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Check metadata
  checkType     HealthCheckType @map("check_type")
  triggerSource String          @map("trigger_source") @db.VarChar(50) // 'sync' | 'manual' | 'daily-cron'

  // Import check results
  importStatus HealthStatus @map("import_status")
  importError  String?      @map("import_error") @db.Text
  importTimeMs Int?         @map("import_time_ms")

  // Execution check results
  executionStatus HealthStatus @map("execution_status")
  executionError  String?      @map("execution_error") @db.Text
  executionTimeMs Int?         @map("execution_time_ms")
  testParameters  Json?        @map("test_parameters") @db.JsonB

  // Overall status
  overallStatus HealthStatus @map("overall_status")

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")

  @@index([toolId])
  @@index([checkType])
  @@index([overallStatus])
  @@index([createdAt])
  @@map("health_checks")
}

/// Health status enum - tracks health check results
enum HealthStatus {
  UNKNOWN // Not yet checked
  HEALTHY // Passed health check
  BROKEN  // Failed health check
}

/// Health check type enum - types of health checks performed
enum HealthCheckType {
  IMPORT    // Only import check
  EXECUTION // Only execution check
  FULL      // Both import and execution
}

/// StatsSnapshot - daily snapshot of registry statistics for historical tracking
model StatsSnapshot {
  id String @id @default(cuid())

  // Snapshot date (one per day)
  date DateTime @unique @db.Date

  // Registry Overview
  totalTools      Int @default(0) @map("total_tools")
  totalPackages   Int @default(0) @map("total_packages")
  officialTools   Int @default(0) @map("official_tools")
  officialPackages Int @default(0) @map("official_packages")
  toolsWithSchema Int @default(0) @map("tools_with_schema")

  // Downloads & Stars
  totalNpmDownloads Int @default(0) @map("total_npm_downloads")
  totalGithubStars  Int @default(0) @map("total_github_stars")

  // Health Status Counts
  importHealthy   Int @default(0) @map("import_healthy")
  importBroken    Int @default(0) @map("import_broken")
  importUnknown   Int @default(0) @map("import_unknown")
  executionHealthy Int @default(0) @map("execution_healthy")
  executionBroken  Int @default(0) @map("execution_broken")
  executionUnknown Int @default(0) @map("execution_unknown")

  // Quality Distribution (stored as JSON for flexibility)
  qualityDistribution Json? @map("quality_distribution") @db.JsonB

  // Package Tiers
  tiersMinimal Int @default(0) @map("tiers_minimal")
  tiersRich    Int @default(0) @map("tiers_rich")

  // Execution Stats (daily)
  executionsTotal      Int @default(0) @map("executions_total")
  executionsSuccessful Int @default(0) @map("executions_successful")
  executionsFailed     Int @default(0) @map("executions_failed")
  executionsAvgTimeMs  Int? @map("executions_avg_time_ms")

  // Token Usage (daily)
  tokensInput    BigInt @default(0) @map("tokens_input")
  tokensOutput   BigInt @default(0) @map("tokens_output")
  tokensTotal    BigInt @default(0) @map("tokens_total")
  tokensCostUsd  Decimal? @map("tokens_cost_usd") @db.Decimal(10, 4)

  // Health Checks (daily)
  healthChecksRun Int @default(0) @map("health_checks_run")

  // Category Breakdown (stored as JSON)
  categories Json? @db.JsonB

  // Social Proof Fields (added for homepage real data)
  activeDevs7d     Int @default(0) @map("active_devs_7d")
  totalCollections Int @default(0) @map("total_collections")
  totalAgents      Int @default(0) @map("total_agents")
  totalSimulations Int @default(0) @map("total_simulations")

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")

  @@index([date])
  @@map("stats_snapshots")
}

/// PageView - daily-bucketed view counts for entities (tools, collections, agents)
model PageView {
  id         String   @id @default(cuid())
  entityType String   @map("entity_type") @db.VarChar(20) // 'tool' | 'collection' | 'agent'
  entityId   String   @map("entity_id")
  viewCount  Int      @default(0) @map("view_count")
  date       DateTime @db.Date

  @@unique([entityType, entityId, date])
  @@index([entityType, entityId])
  @@index([date])
  @@map("page_views")
}

// ============================================================================
// Better Auth Models
// ============================================================================

/// User table - stores authenticated users
model User {
  id            String    @id @default(cuid())
  name          String
  email         String    @unique
  emailVerified Boolean   @default(false) @map("email_verified")
  image         String?
  username      String?   @unique @db.VarChar(30) // URL-friendly username (nullable for migration)

  // Tier for rate limiting and feature access
  tier          UserTier  @default(FREE)

  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  sessions         Session[]
  accounts         Account[]
  collections      Collection[]
  agents           Agent[]
  apiKeys          UserApiKey[]
  toolLikes        ToolLike[]
  toolRatings      ToolRating[]
  toolReviews      ToolReview[]
  collectionLikes  CollectionLike[]
  agentLikes       AgentLike[]
  activities       UserActivity[]
  bridgeConnection BridgeConnection?
  tpmjsApiKeys     TpmjsApiKey[]     @relation("UserTpmjsApiKeys")
  usageSummaries   ApiUsageSummary[] @relation("UserUsageSummaries")

  @@index([username])
  @@map("users")
}

/// Session table - stores user sessions
model Session {
  id        String   @id @default(cuid())
  userId    String   @map("user_id")
  token     String   @unique
  expiresAt DateTime @map("expires_at")
  ipAddress String?  @map("ip_address")
  userAgent String?  @map("user_agent")

  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

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

  @@index([userId])
  @@map("sessions")
}

/// Account table - stores auth provider accounts (including email/password)
model Account {
  id           String    @id @default(cuid())
  userId       String    @map("user_id")
  accountId    String    @map("account_id")
  providerId   String    @map("provider_id")
  accessToken  String?   @map("access_token") @db.Text
  refreshToken String?   @map("refresh_token") @db.Text
  idToken      String?   @map("id_token") @db.Text
  expiresAt    DateTime? @map("expires_at")
  password     String?

  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

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

  @@index([userId])
  @@map("accounts")
}

/// Verification table - stores email verification tokens
model Verification {
  id         String   @id @default(cuid())
  identifier String
  value      String
  expiresAt  DateTime @map("expires_at")

  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@map("verifications")
}

// ============================================================================
// Collection Models
// ============================================================================

/// Collection - user-created groups of tools
model Collection {
  id          String   @id @default(cuid())

  // Owner relationship
  userId      String   @map("user_id")
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  // Collection metadata
  name        String   @db.VarChar(100)
  slug        String?  @db.VarChar(50) // URL-friendly identifier (nullable for migration)
  description String?  @db.VarChar(500)
  isPublic    Boolean  @default(false) @map("is_public")
  likeCount   Int      @default(0) @map("like_count")

  // View tracking (denormalized, rolled up daily)
  viewCount   Int      @default(0) @map("view_count")

  // Executor configuration (optional - uses system default if not set)
  executorType   String? @map("executor_type") @db.VarChar(50)
  executorConfig Json?   @map("executor_config") @db.JsonB

  // Tool environment variables (encrypted JSON: { "KEY": "value" })
  // These are passed to tools when executed
  envVars        Json?   @map("env_vars") @db.JsonB

  // Fork tracking - for "fork to use" model
  forkedFromId String?     @map("forked_from_id")
  forkedFrom   Collection? @relation("CollectionForks", fields: [forkedFromId], references: [id], onDelete: SetNull)
  forks        Collection[] @relation("CollectionForks")
  forkCount    Int         @default(0) @map("fork_count")

  // AI-generated use cases
  useCases            Json?     @map("use_cases") @db.JsonB
  useCasesGeneratedAt DateTime? @map("use_cases_generated_at")

  // AI-generated skills documentation
  skillsMarkdown      String?   @map("skills_markdown") @db.Text
  skillsGeneratedAt   DateTime? @map("skills_generated_at")

  // RealSkills lazy seeding state
  skillsSeeded        Boolean   @default(false) @map("skills_seeded")
  skillsSeedingAt     DateTime? @map("skills_seeding_at")

  // Timestamps
  createdAt   DateTime @default(now()) @map("created_at")
  updatedAt   DateTime @updatedAt @map("updated_at")

  // Relations
  tools                  CollectionTool[]
  agents                 AgentCollection[]
  likes                  CollectionLike[]
  bridgeTools            CollectionBridgeTool[]
  scenarios              Scenario[]
  skillsGenerationJobs   SkillsGenerationJob[]
  skillQuestions         SkillQuestion[]
  skills                 Skill[]
  skillSessions          SkillSession[]

  // Unique constraint: user can't have duplicate collection slugs
  @@unique([userId, slug])
  @@index([userId])
  @@index([slug])
  @@index([isPublic])
  @@index([likeCount])
  @@index([viewCount])
  @@index([createdAt])
  @@index([forkedFromId])
  @@index([forkCount])
  @@map("collections")
}

/// CollectionTool - junction table for many-to-many relationship between collections and tools
model CollectionTool {
  id           String     @id @default(cuid())

  // Relationships
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
  toolId       String     @map("tool_id")
  tool         Tool       @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Ordering - allows users to reorder tools within a collection
  position     Int        @default(0)

  // Optional user notes about why this tool is in the collection
  note         String?    @db.VarChar(500)

  // Timestamps
  addedAt      DateTime   @default(now()) @map("added_at")

  // Unique constraint: tool can only be in a collection once
  @@unique([collectionId, toolId])
  @@index([collectionId])
  @@index([toolId])
  @@map("collection_tools")
}

// ============================================================================
// Agent Models
// ============================================================================

/// AI Provider enum - supported LLM providers
enum AIProvider {
  OPENAI
  ANTHROPIC
  GOOGLE
  GROQ
  MISTRAL
}

/// Message role enum - conversation message types
enum MessageRole {
  USER
  ASSISTANT
  TOOL
  SYSTEM
}

/// Agent - user-owned AI agent configurations
model Agent {
  id                   String     @id @default(cuid())

  // Owner relationship
  userId               String     @map("user_id")
  user                 User       @relation(fields: [userId], references: [id], onDelete: Cascade)

  // Agent identity
  uid                  String     @unique @db.VarChar(50) // URL-friendly identifier
  name                 String     @db.VarChar(100)
  description          String?    @db.VarChar(500)

  // Model configuration
  provider             AIProvider
  modelId              String     @map("model_id") @db.VarChar(100)
  systemPrompt         String?    @map("system_prompt") @db.Text
  temperature          Float      @default(0.7)
  maxToolCallsPerTurn  Int        @default(20) @map("max_tool_calls_per_turn")
  maxMessagesInContext Int        @default(10) @map("max_messages_in_context")

  // Visibility
  isPublic             Boolean    @default(true) @map("is_public")
  likeCount            Int        @default(0) @map("like_count")

  // View tracking (denormalized, rolled up daily)
  viewCount            Int        @default(0) @map("view_count")

  // Executor configuration (optional - uses system default if not set)
  // Agent executor overrides collection executor overrides system default
  executorType         String?    @map("executor_type") @db.VarChar(50)
  executorConfig       Json?      @map("executor_config") @db.JsonB

  // Tool environment variables (encrypted JSON: { "KEY": "value" })
  // Agent env vars override collection env vars, otherwise merged
  envVars              Json?      @map("env_vars") @db.JsonB

  // Fork tracking - for "fork to use" model
  forkedFromId         String?    @map("forked_from_id")
  forkedFrom           Agent?     @relation("AgentForks", fields: [forkedFromId], references: [id], onDelete: SetNull)
  forks                Agent[]    @relation("AgentForks")
  forkCount            Int        @default(0) @map("fork_count")

  // Timestamps
  createdAt            DateTime   @default(now()) @map("created_at")
  updatedAt            DateTime   @updatedAt @map("updated_at")

  // Relations
  collections          AgentCollection[]
  tools                AgentTool[]
  conversations        Conversation[]
  likes                AgentLike[]

  @@unique([userId, name])
  @@index([userId])
  @@index([uid])
  @@index([isPublic])
  @@index([likeCount])
  @@index([viewCount])
  @@index([createdAt])
  @@index([forkedFromId])
  @@index([forkCount])
  @@map("agents")
}

/// AgentCollection - junction table for Agent -> Collection (many-to-many)
model AgentCollection {
  id           String     @id @default(cuid())

  // Relationships
  agentId      String     @map("agent_id")
  agent        Agent      @relation(fields: [agentId], references: [id], onDelete: Cascade)
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Ordering
  position     Int        @default(0)

  // Timestamps
  addedAt      DateTime   @default(now()) @map("added_at")

  @@unique([agentId, collectionId])
  @@index([agentId])
  @@index([collectionId])
  @@map("agent_collections")
}

/// AgentTool - junction table for Agent -> Tool (many-to-many)
model AgentTool {
  id        String   @id @default(cuid())

  // Relationships
  agentId   String   @map("agent_id")
  agent     Agent    @relation(fields: [agentId], references: [id], onDelete: Cascade)
  toolId    String   @map("tool_id")
  tool      Tool     @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Ordering
  position  Int      @default(0)

  // Timestamps
  addedAt   DateTime @default(now()) @map("added_at")

  @@unique([agentId, toolId])
  @@index([agentId])
  @@index([toolId])
  @@map("agent_tools")
}

/// UserApiKey - encrypted API keys/env vars per user
model UserApiKey {
  id           String   @id @default(cuid())

  // Owner relationship
  userId       String   @map("user_id")
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  // Key identification (e.g. OPENAI_API_KEY, MY_SECRET, etc.)
  keyName      String   @map("key_name") @db.VarChar(100)

  // Encrypted key storage
  encryptedKey String   @map("encrypted_key") @db.Text
  keyIv        String   @map("key_iv") @db.VarChar(32)
  keyHint      String?  @map("key_hint") @db.VarChar(10) // Last 4 chars

  // Timestamps
  createdAt    DateTime @default(now()) @map("created_at")
  updatedAt    DateTime @updatedAt @map("updated_at")

  @@unique([userId, keyName])
  @@index([userId])
  @@map("user_api_keys")
}

/// Conversation - chat session with an agent
model Conversation {
  id          String    @id @default(cuid())

  // Agent relationship
  agentId     String    @map("agent_id")
  agent       Agent     @relation(fields: [agentId], references: [id], onDelete: Cascade)

  // Conversation identity
  slug        String    @db.VarChar(100) // User-chosen unique ID

  // Metadata
  title       String?   @db.VarChar(200)

  // Timestamps
  createdAt   DateTime  @default(now()) @map("created_at")
  updatedAt   DateTime  @updatedAt @map("updated_at")

  // Relations
  messages    Message[]

  @@unique([agentId, slug])
  @@index([agentId])
  @@index([createdAt])
  @@map("conversations")
}

/// Message - individual message in a conversation
model Message {
  id             String       @id @default(cuid())

  // Conversation relationship
  conversationId String       @map("conversation_id")
  conversation   Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  // Message content
  role           MessageRole
  content        String       @db.Text

  // Tool call metadata (for role=ASSISTANT with tool calls)
  toolCalls      Json?        @map("tool_calls") @db.JsonB

  // Tool result metadata (for role=TOOL)
  toolCallId     String?      @map("tool_call_id") @db.VarChar(100)
  toolName       String?      @map("tool_name") @db.VarChar(200)
  toolResult     Json?        @map("tool_result") @db.JsonB

  // Token tracking
  inputTokens    Int?         @map("input_tokens")
  outputTokens   Int?         @map("output_tokens")

  // Timestamps
  createdAt      DateTime     @default(now()) @map("created_at")

  @@index([conversationId])
  @@index([createdAt])
  @@map("messages")
}

// ============================================================================
// Like Models
// ============================================================================

/// ToolLike - tracks users who liked a tool
model ToolLike {
  id        String   @id @default(cuid())

  // Relationships
  userId    String   @map("user_id")
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  toolId    String   @map("tool_id")
  tool      Tool     @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")

  @@unique([userId, toolId])
  @@index([toolId])
  @@index([userId])
  @@map("tool_likes")
}

/// CollectionLike - tracks users who liked a collection
model CollectionLike {
  id           String     @id @default(cuid())

  // Relationships
  userId       String     @map("user_id")
  user         User       @relation(fields: [userId], references: [id], onDelete: Cascade)
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Timestamps
  createdAt    DateTime   @default(now()) @map("created_at")

  @@unique([userId, collectionId])
  @@index([collectionId])
  @@index([userId])
  @@map("collection_likes")
}

/// AgentLike - tracks users who liked an agent
model AgentLike {
  id        String   @id @default(cuid())

  // Relationships
  userId    String   @map("user_id")
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  agentId   String   @map("agent_id")
  agent     Agent    @relation(fields: [agentId], references: [id], onDelete: Cascade)

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")

  @@unique([userId, agentId])
  @@index([agentId])
  @@index([userId])
  @@map("agent_likes")
}

/// ToolRating - user ratings for tools (1-5 stars)
model ToolRating {
  id        String   @id @default(cuid())

  // Relationships
  userId    String   @map("user_id")
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  toolId    String   @map("tool_id")
  tool      Tool     @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Rating value (1-5)
  rating    Int      @db.SmallInt

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@unique([userId, toolId])
  @@index([toolId])
  @@index([userId])
  @@index([rating])
  @@map("tool_ratings")
}

/// ToolReview - user reviews for tools
model ToolReview {
  id        String   @id @default(cuid())

  // Relationships
  userId    String   @map("user_id")
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  toolId    String   @map("tool_id")
  tool      Tool     @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Review content
  title     String?  @db.VarChar(200)
  content   String   @db.Text
  rating    Int      @db.SmallInt // 1-5, denormalized for convenience

  // Moderation
  isApproved Boolean @default(true) @map("is_approved")
  isHidden   Boolean @default(false) @map("is_hidden")

  // Helpful votes
  helpfulCount Int   @default(0) @map("helpful_count")

  // Timestamps
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@unique([userId, toolId])
  @@index([toolId])
  @@index([userId])
  @@index([rating])
  @@index([isApproved, isHidden])
  @@index([createdAt])
  @@map("tool_reviews")
}

// ============================================================================
// Activity Stream Models
// ============================================================================

/// Activity type enum - types of user activities tracked
enum ActivityType {
  AGENT_CREATED
  AGENT_UPDATED
  AGENT_DELETED
  AGENT_CLONED
  AGENT_FORKED
  AGENT_TOOL_ADDED
  AGENT_TOOL_REMOVED
  AGENT_COLLECTION_ADDED
  AGENT_COLLECTION_REMOVED
  COLLECTION_CREATED
  COLLECTION_UPDATED
  COLLECTION_DELETED
  COLLECTION_CLONED
  COLLECTION_FORKED
  COLLECTION_TOOL_ADDED
  COLLECTION_TOOL_REMOVED
  TOOL_LIKED
  TOOL_UNLIKED
  COLLECTION_LIKED
  COLLECTION_UNLIKED
  AGENT_LIKED
  AGENT_UNLIKED
}

/// UserActivity - tracks user actions for activity stream
model UserActivity {
  id           String       @id @default(cuid())

  // Owner relationship
  userId       String       @map("user_id")
  user         User         @relation(fields: [userId], references: [id], onDelete: Cascade)

  // Activity type
  type         ActivityType

  // Optional entity references (for linking to entities if they still exist)
  agentId      String?      @map("agent_id")
  collectionId String?      @map("collection_id")
  toolId       String?      @map("tool_id")

  // Denormalized fields (stored at creation time for display even after entity deletion)
  targetName   String       @map("target_name") @db.VarChar(200)
  targetType   String       @map("target_type") @db.VarChar(50) // 'agent' | 'collection' | 'tool'

  // Additional context (e.g., toolName when adding to collection)
  metadata     Json?        @db.JsonB

  // Timestamps
  createdAt    DateTime     @default(now()) @map("created_at")

  @@index([userId])
  @@index([userId, createdAt])
  @@index([type])
  @@index([createdAt])
  @@map("user_activities")
}

// ============================================================================
// Endpoint Health Monitoring Models
// ============================================================================

/// EndpointHealthReport - stores health check results from GitHub Actions or other monitoring
model EndpointHealthReport {
  id            String   @id @default(cuid())

  // Report metadata
  timestamp     DateTime
  source        String   @db.VarChar(50) // 'github-actions' | 'manual' | 'uptime-robot' etc.
  runId         String?  @map("run_id") @db.VarChar(100) // GitHub Actions run ID

  // Check results
  checks        Json     @db.JsonB // { check_name: 'pass' | 'fail' }
  passCount     Int      @map("pass_count")
  failCount     Int      @map("fail_count")
  totalChecks   Int      @map("total_checks")
  overallStatus String   @map("overall_status") @db.VarChar(20) // 'healthy' | 'degraded' | 'down'

  // Timestamps
  createdAt     DateTime @default(now()) @map("created_at")

  @@index([timestamp])
  @@index([overallStatus])
  @@index([source])
  @@map("endpoint_health_reports")
}

// ============================================================================
// MCP Bridge Models
// ============================================================================

/// BridgeConnection - tracks active bridge connections from users
model BridgeConnection {
  id            String    @id @default(cuid())

  // Owner relationship
  userId        String    @unique @map("user_id")
  user          User      @relation(fields: [userId], references: [id], onDelete: Cascade)

  // Connection state
  status        String    @default("disconnected") @db.VarChar(20) // 'connected' | 'disconnected'
  socketId      String?   @map("socket_id") @db.VarChar(100) // Internal socket identifier for routing

  // Cached tool definitions from bridge
  tools         Json      @default("[]") @db.JsonB

  // Metadata
  lastSeen      DateTime? @map("last_seen")
  clientVersion String?   @map("client_version") @db.VarChar(20)
  clientOS      String?   @map("client_os") @db.VarChar(50)

  // Timestamps
  createdAt     DateTime  @default(now()) @map("created_at")
  updatedAt     DateTime  @updatedAt @map("updated_at")

  @@index([status])
  @@map("bridge_connections")
}

/// CollectionBridgeTool - tracks which bridge tools are added to collections
model CollectionBridgeTool {
  id           String     @id @default(cuid())

  // Collection relationship
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Bridge tool reference
  serverId     String     @map("server_id") @db.VarChar(100) // e.g., "chrome-devtools"
  toolName     String     @map("tool_name") @db.VarChar(100) // e.g., "screenshot"

  // Display customization
  displayName  String?    @map("display_name") @db.VarChar(100) // Override tool name in MCP
  note         String?    @db.VarChar(500) // User notes

  // Timestamps
  createdAt    DateTime   @default(now()) @map("created_at")
  updatedAt    DateTime   @updatedAt @map("updated_at")

  @@unique([collectionId, serverId, toolName])
  @@index([collectionId])
  @@map("collection_bridge_tools")
}

// ============================================================================
// API Key & Usage Tracking Models
// ============================================================================

/// User tier enum - determines rate limits and feature access
enum UserTier {
  FREE
  PRO
  ENTERPRISE
}

/// TpmjsApiKey - user-owned API keys for programmatic access
model TpmjsApiKey {
  id          String    @id @default(cuid())

  // Owner relationship
  userId      String    @map("user_id")
  user        User      @relation("UserTpmjsApiKeys", fields: [userId], references: [id], onDelete: Cascade)

  // Key identification
  name        String    @db.VarChar(100) // User-provided name (e.g., "Production Server")
  keyHash     String    @unique @map("key_hash") @db.VarChar(64) // SHA-256 hash (never store raw keys)
  keyPrefix   String    @map("key_prefix") @db.VarChar(20) // First 16 chars for identification (tpmjs_sk_abc123...)

  // Permissions
  scopes      String[]  @default([]) // ["mcp:execute", "agent:chat", "bridge:connect", "usage:read"]

  // Rate limiting (overrides tier default if set)
  rateLimit   Int?      @map("rate_limit") // Requests per hour (null = use tier default)

  // Status
  isActive    Boolean   @default(true) @map("is_active")
  lastUsedAt  DateTime? @map("last_used_at")
  expiresAt   DateTime? @map("expires_at")

  // Timestamps
  createdAt   DateTime  @default(now()) @map("created_at")
  updatedAt   DateTime  @updatedAt @map("updated_at")

  // Relations
  usageRecords ApiUsageRecord[]

  @@index([userId])
  @@index([keyHash])
  @@index([keyPrefix])
  @@index([isActive])
  @@map("tpmjs_api_keys")
}

/// ApiUsageRecord - individual API request logs (kept for 30 days)
model ApiUsageRecord {
  id           String      @id @default(cuid())

  // API key relationship
  apiKeyId     String      @map("api_key_id")
  apiKey       TpmjsApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)

  // Request details
  endpoint     String      @db.VarChar(500)
  method       String      @db.VarChar(10) // GET, POST, etc.
  statusCode   Int         @map("status_code")
  latencyMs    Int         @map("latency_ms")

  // Resource tracking
  resourceType String?     @map("resource_type") @db.VarChar(50) // "mcp" | "agent" | "bridge" | "collection"
  resourceId   String?     @map("resource_id") @db.VarChar(100) // Collection ID, Agent ID, etc.

  // LLM usage (if applicable)
  tokensIn     Int?        @map("tokens_in")
  tokensOut    Int?        @map("tokens_out")
  model        String?     @db.VarChar(50) // e.g., "gpt-4o-mini"

  // Error tracking
  errorCode    String?     @map("error_code") @db.VarChar(50)
  errorMessage String?     @map("error_message") @db.Text

  // Client metadata
  userAgent    String?     @map("user_agent") @db.VarChar(500)
  ipAddress    String?     @map("ip_address") @db.VarChar(45) // IPv4 or IPv6

  // Timestamps
  createdAt    DateTime    @default(now()) @map("created_at")

  @@index([apiKeyId])
  @@index([createdAt])
  @@index([endpoint])
  @@index([resourceType, resourceId])
  @@map("api_usage_records")
}

/// ApiUsageSummary - aggregated usage summaries (hourly/daily rollups)
model ApiUsageSummary {
  id                 String   @id @default(cuid())

  // User relationship
  userId             String   @map("user_id")
  user               User     @relation("UserUsageSummaries", fields: [userId], references: [id], onDelete: Cascade)

  // Optional API key (null for user-level summaries)
  apiKeyId           String?  @map("api_key_id")

  // Time period
  periodType         String   @map("period_type") @db.VarChar(20) // "hourly" | "daily" | "monthly"
  periodStart        DateTime @map("period_start")

  // Request counts
  totalRequests      Int      @default(0) @map("total_requests")
  successRequests    Int      @default(0) @map("success_requests")
  errorRequests      Int      @default(0) @map("error_requests")

  // Endpoint breakdown (JSON: { "/api/mcp/...": 100, ... })
  endpointCounts     Json     @default("{}") @map("endpoint_counts") @db.JsonB

  // LLM usage totals
  totalTokensIn      Int      @default(0) @map("total_tokens_in")
  totalTokensOut     Int      @default(0) @map("total_tokens_out")

  // Performance
  avgLatencyMs       Float    @default(0) @map("avg_latency_ms")
  p95LatencyMs       Float    @default(0) @map("p95_latency_ms")

  // Cost estimation (in cents)
  estimatedCostCents Int      @default(0) @map("estimated_cost_cents")

  // Timestamps
  createdAt          DateTime @default(now()) @map("created_at")
  updatedAt          DateTime @updatedAt @map("updated_at")

  @@unique([userId, apiKeyId, periodType, periodStart])
  @@index([userId])
  @@index([periodType, periodStart])
  @@map("api_usage_summaries")
}

// ============================================================================
// Scenario Models (Integration Testing for Collections)
// ============================================================================

/// Scenario - AI-generated test scenarios for collections
model Scenario {
  id           String      @id @default(cuid())

  // Collection relationship (nullable for orphaned scenarios)
  collectionId String?     @map("collection_id")
  collection   Collection? @relation(fields: [collectionId], references: [id], onDelete: SetNull)

  // Content
  prompt       String      @db.Text // AI-generated free-form prompt
  name         String?     @db.VarChar(200) // Optional human-readable name
  description  String?     @db.Text

  // Validation (optional assertions)
  assertions   Json?       @db.JsonB // { regex?: string[], schema?: object }

  // AI-generated metadata
  tags         String[]    @default([]) @db.Text

  // Quality metrics (streak-based scoring)
  qualityScore      Float   @default(0) @map("quality_score")
  consecutivePasses Int     @default(0) @map("consecutive_passes")
  consecutiveFails  Int     @default(0) @map("consecutive_fails")
  totalRuns         Int     @default(0) @map("total_runs")
  lastRunAt         DateTime? @map("last_run_at")
  lastRunStatus     String?   @map("last_run_status") @db.VarChar(20) // 'pass' | 'fail' | 'error'

  // Timestamps
  createdAt    DateTime    @default(now()) @map("created_at")
  updatedAt    DateTime    @updatedAt @map("updated_at")

  // Relations
  runs         ScenarioRun[]
  embedding    ScenarioEmbedding?
  useCase      UseCase?

  @@index([collectionId])
  @@index([qualityScore])
  @@index([createdAt])
  @@index([lastRunStatus])
  @@map("scenarios")
}

/// ScenarioEmbedding - vector embeddings for scenario similarity detection
model ScenarioEmbedding {
  id         String   @id @default(cuid())

  // Scenario relationship
  scenarioId String   @unique @map("scenario_id")
  scenario   Scenario @relation(fields: [scenarioId], references: [id], onDelete: Cascade)

  // Embedding data
  embedding  Json     @db.JsonB // Array of floats (1536 dims for text-embedding-3-small)
  model      String   @default("text-embedding-3-small") @db.VarChar(50)

  // Timestamps
  createdAt  DateTime @default(now()) @map("created_at")

  @@index([scenarioId])
  @@map("scenario_embeddings")
}

/// ScenarioRun - individual execution records for scenarios
model ScenarioRun {
  id         String   @id @default(cuid())

  // Scenario relationship
  scenarioId String   @map("scenario_id")
  scenario   Scenario @relation(fields: [scenarioId], references: [id], onDelete: Cascade)

  // Execution context
  userId     String   @map("user_id") // Who triggered the run
  agentId    String?  @map("agent_id") // Ephemeral agent ID (for debugging)

  // Status
  status     String   @db.VarChar(20) // 'pending' | 'running' | 'pass' | 'fail' | 'error'
  retryCount Int      @default(0) @map("retry_count")

  // Results
  conversation Json?   @db.JsonB // Full message history
  output       String? @db.Text // Final output from agent
  errorLog     String? @map("error_log") @db.Text // Full error logs (private to owner)

  // LLM Evaluation
  evaluatorModel   String? @map("evaluator_model") @db.VarChar(50) // e.g., "claude-3.5-sonnet"
  evaluatorVerdict String? @map("evaluator_verdict") @db.VarChar(10) // 'pass' | 'fail'
  evaluatorReason  String? @map("evaluator_reason") @db.Text // Explanation

  // Assertions
  assertionResults Json? @map("assertion_results") @db.JsonB // { passed: string[], failed: string[] }

  // Cost tracking
  inputTokens     Int?    @map("input_tokens")
  outputTokens    Int?    @map("output_tokens")
  totalTokens     Int?    @map("total_tokens")
  executionTimeMs Int?    @map("execution_time_ms")
  estimatedCost   Decimal? @map("estimated_cost") @db.Decimal(10, 6)

  // Timestamps
  startedAt   DateTime? @map("started_at")
  completedAt DateTime? @map("completed_at")
  createdAt   DateTime  @default(now()) @map("created_at")

  @@index([scenarioId])
  @@index([userId])
  @@index([status])
  @@index([createdAt])
  @@map("scenario_runs")
}

/// ScenarioQuota - daily usage quotas for scenario runs
model ScenarioQuota {
  id          String   @id @default(cuid())

  // User relationship
  userId      String   @unique @map("user_id")

  // Quota configuration
  dailyLimit  Int      @default(50) @map("daily_limit") // Runs per day
  dailyUsed   Int      @default(0) @map("daily_used")
  lastResetAt DateTime @default(now()) @map("last_reset_at")

  // Timestamps
  createdAt   DateTime @default(now()) @map("created_at")
  updatedAt   DateTime @updatedAt @map("updated_at")

  @@index([userId])
  @@map("scenario_quotas")
}

// ============================================================================
// Use Cases Models (Marketing Content from Scenarios)
// ============================================================================

/// Persona - user personas for use case targeting (AI-populated)
model Persona {
  id          String   @id @default(cuid())
  name        String   @unique @db.VarChar(100)
  slug        String   @unique @db.VarChar(100)
  description String?  @db.Text
  icon        String?  @db.VarChar(50) // emoji or icon name
  createdAt   DateTime @default(now()) @map("created_at")

  // Relations
  useCases    UseCasePersona[]

  @@index([slug])
  @@map("personas")
}

/// Industry - industries for use case categorization (AI-populated)
model Industry {
  id          String    @id @default(cuid())
  name        String    @unique @db.VarChar(100)
  slug        String    @unique @db.VarChar(100)
  description String?   @db.Text
  icon        String?   @db.VarChar(50)
  parentId    String?   @map("parent_id")
  parent      Industry? @relation("IndustryHierarchy", fields: [parentId], references: [id])
  children    Industry[] @relation("IndustryHierarchy")
  createdAt   DateTime  @default(now()) @map("created_at")

  // Relations
  useCases    UseCaseIndustry[]

  @@index([parentId])
  @@index([slug])
  @@map("industries")
}

/// Category - categories for use case organization (AI-populated)
model Category {
  id          String          @id @default(cuid())
  name        String          @unique @db.VarChar(100)
  slug        String          @unique @db.VarChar(100)
  type        String          @map("type") @db.VarChar(50) // 'functional', 'business-process', 'technical'
  description String?         @db.Text
  createdAt   DateTime        @default(now()) @map("created_at")

  // Relations
  useCases    UseCaseCategory[]

  @@index([type])
  @@index([slug])
  @@map("categories")
}

/// UseCase - auto-generated marketing content from qualifying scenarios
model UseCase {
  id                String            @id @default(cuid())
  scenarioId        String            @unique @map("scenario_id")
  scenario          Scenario          @relation(fields: [scenarioId], references: [id], onDelete: Cascade)

  // SEO-friendly slug
  slug              String            @db.VarChar(200)

  // AI-generated marketing content
  marketingTitle    String            @map("marketing_title") @db.VarChar(200)
  marketingDesc     String            @map("marketing_desc") @db.Text
  roiEstimate       String?           @map("roi_estimate") @db.Text  // "Saves ~10 hours/week"
  businessValue     String?           @map("business_value") @db.Text  // Human-readable benefit
  problemStatement  String?           @map("problem_statement") @db.Text  // What problem it solves
  solutionNarrative String?          @map("solution_narrative") @db.Text  // How it works

  // Ranking (computed nightly)
  rankScore         Float             @default(0) @map("rank_score")
  lastRankedAt      DateTime          @map("last_ranked_at")

  // Timestamps
  createdAt         DateTime          @default(now()) @map("created_at")
  updatedAt         DateTime          @updatedAt @map("updated_at")
  lastRegeneratedAt DateTime?         @map("last_regenerated_at")

  // Relations
  personas          UseCasePersona[]
  industries        UseCaseIndustry[]
  categories        UseCaseCategory[]
  socialProof       SocialProof?

  @@index([scenarioId])
  @@index([slug])
  @@index([rankScore])
  @@index([lastRankedAt])
  @@index([lastRegeneratedAt])
  @@map("use_cases")
}

/// UseCasePersona - junction table for UseCase <-> Persona
model UseCasePersona {
  useCaseId    String  @map("use_case_id")
  personaId    String  @map("persona_id")
  useCase      UseCase @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
  persona      Persona  @relation(fields: [personaId], references: [id], onDelete: Cascade)
  relevance    Float?  @map("relevance") // Future: relevance score for this persona

  @@id([useCaseId, personaId])
  @@index([useCaseId])
  @@index([personaId])
  @@map("use_case_personas")
}

/// UseCaseIndustry - junction table for UseCase <-> Industry
model UseCaseIndustry {
  useCaseId  String   @map("use_case_id")
  industryId String   @map("industry_id")
  useCase    UseCase  @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
  industry   Industry @relation(fields: [industryId], references: [id], onDelete: Cascade)

  @@id([useCaseId, industryId])
  @@index([useCaseId])
  @@index([industryId])
  @@map("use_case_industries")
}

/// UseCaseCategory - junction table for UseCase <-> Category
model UseCaseCategory {
  useCaseId  String   @map("use_case_id")
  categoryId String   @map("category_id")
  useCase    UseCase  @relation(fields: [useCaseId], references: [id], onDelete: Cascade)
  category   Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)

  @@id([useCaseId, categoryId])
  @@index([useCaseId])
  @@index([categoryId])
  @@map("use_case_categories")
}

/// SocialProof - cached metrics from scenario runs for use cases
model SocialProof {
  id               String   @id @default(cuid())
  useCaseId        String   @unique @map("use_case_id")
  useCase          UseCase  @relation(fields: [useCaseId], references: [id], onDelete: Cascade)

  qualityScore     Float    @map("quality_score")
  totalRuns        Int      @map("total_runs")
  consecutivePasses Int     @map("consecutive_passes")
  lastRunStatus    String?  @map("last_run_status") @db.VarChar(20)
  lastRunAt        DateTime? @map("last_run_at")

  // Computed display fields
  successRate      Float?   @map("success_rate")
  lastRunAgo       String?  @map("last_run_ago") // "2 days ago"

  updatedAt        DateTime @updatedAt @map("updated_at")

  @@index([useCaseId])
  @@index([qualityScore])
  @@index([totalRuns])
  @@map("social_proofs")
}

// ============================================================================
// Skills Generation Models (Chunked Generation for Large Collections)
// ============================================================================

/// ToolSkillsCache - per-tool cached skills markdown section
model ToolSkillsCache {
  id              String   @id @default(cuid())

  // Tool relationship
  toolId          String   @unique @map("tool_id")
  tool            Tool     @relation(fields: [toolId], references: [id], onDelete: Cascade)

  // Cached markdown section for this tool
  skillsMarkdown  String   @map("skills_markdown") @db.Text

  // Timestamps
  generatedAt     DateTime @default(now()) @map("generated_at")

  @@index([toolId])
  @@map("tool_skills_cache")
}

/// SkillsGenerationJob - tracks chunked skills.md generation progress
model SkillsGenerationJob {
  id               String     @id @default(cuid())

  // Collection relationship
  collectionId     String     @map("collection_id")
  collection       Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Job status
  status           String     @default("pending") @db.VarChar(20) // 'pending' | 'processing' | 'completed' | 'failed'

  // Progress tracking
  currentBatch     Int        @default(0) @map("current_batch")
  totalBatches     Int        @map("total_batches")
  completedToolIds String[]   @default([]) @map("completed_tool_ids")

  // Error tracking
  error            String?    @db.Text

  // Timestamps
  createdAt        DateTime   @default(now()) @map("created_at")
  updatedAt        DateTime   @updatedAt @map("updated_at")

  @@index([collectionId])
  @@index([status])
  @@map("skills_generation_jobs")
}

// ============================================================================
// Omega Models (AI Agent Chat with Full Registry Access)
// ============================================================================

/// OmegaConversation - chat session for Omega AI agent
model OmegaConversation {
  id                String   @id @default(cuid())

  // Owner relationship
  ownerId           String   @map("owner_id")

  // Conversation metadata
  title             String?  @db.VarChar(200)

  // Execution state
  executionState    String   @default("idle") @map("execution_state") @db.VarChar(20) // idle, running, paused, cancelled

  // Token tracking (aggregate across all messages)
  inputTokensTotal  Int      @default(0) @map("input_tokens_total")
  outputTokensTotal Int      @default(0) @map("output_tokens_total")

  // Timestamps
  createdAt         DateTime @default(now()) @map("created_at")
  updatedAt         DateTime @updatedAt @map("updated_at")

  // Relations
  messages          OmegaMessage[]
  participants      OmegaParticipant[]
  toolRuns          OmegaToolRun[]

  @@index([ownerId])
  @@index([createdAt])
  @@map("omega_conversations")
}

/// OmegaMessage - individual message in an Omega conversation
model OmegaMessage {
  id             String   @id @default(cuid())

  // Conversation relationship
  conversationId String   @map("conversation_id")
  conversation   OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  // Message content
  role           MessageRole
  content        String   @db.Text

  // Author info (for multi-user conversations)
  authorId       String?  @map("author_id")
  authorEmail    String?  @map("author_email")
  authorName     String?  @map("author_name") @db.VarChar(100)

  // Tool calls (for ASSISTANT messages)
  toolCalls      Json?    @map("tool_calls") @db.JsonB

  // Token tracking
  inputTokens    Int?     @map("input_tokens")
  outputTokens   Int?     @map("output_tokens")

  // Timestamps
  createdAt      DateTime @default(now()) @map("created_at")

  @@index([conversationId])
  @@index([createdAt])
  @@map("omega_messages")
}

/// OmegaParticipant - tracks users in an Omega conversation
model OmegaParticipant {
  id             String   @id @default(cuid())

  // Conversation relationship
  conversationId String   @map("conversation_id")
  conversation   OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  // User info
  userId         String?  @map("user_id")
  displayName    String   @map("display_name") @db.VarChar(100)
  email          String?

  // Role in conversation
  role           String   @default("collaborator") @db.VarChar(20) // owner, collaborator

  // Timestamps
  joinedAt       DateTime @default(now()) @map("joined_at")

  @@unique([conversationId, userId])
  @@index([conversationId])
  @@map("omega_participants")
}

/// OmegaToolRun - tracks tool executions within Omega conversations
model OmegaToolRun {
  id              String    @id @default(cuid())

  // Conversation relationship
  conversationId  String    @map("conversation_id")
  conversation    OmegaConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  // Message relationship (optional - for linking to specific message)
  messageId       String?   @map("message_id")

  // Tool execution details
  toolName        String    @map("tool_name") @db.VarChar(200)
  input           Json      @db.JsonB
  output          Json?     @db.JsonB
  error           String?   @db.Text

  // Status tracking
  status          String    @db.VarChar(20) // pending, running, success, error

  // Timing
  startedAt       DateTime  @default(now()) @map("started_at")
  completedAt     DateTime? @map("completed_at")
  executionTimeMs Int?      @map("execution_time_ms")

  @@index([conversationId])
  @@index([status])
  @@map("omega_tool_runs")
}

/// OmegaUserSettings - user preferences for Omega
model OmegaUserSettings {
  id                 String   @id @default(cuid())

  // User relationship
  userId             String   @unique @map("user_id")

  // Tool preferences
  pinnedToolIds      String[] @default([]) @map("pinned_tool_ids")
  blockedToolIds     String[] @default([]) @map("blocked_tool_ids")

  // Customization
  customSystemPrompt String?  @map("custom_system_prompt") @db.Text

  // UI preferences
  showDebugMode      Boolean  @default(false) @map("show_debug_mode")

  // Timestamps
  createdAt          DateTime @default(now()) @map("created_at")
  updatedAt          DateTime @updatedAt @map("updated_at")

  @@map("omega_user_settings")
}

// ============================================================================
// RealSkills Models (Living Skills Endpoint - Question-Driven Evolution)
// ============================================================================

/// SkillQuestion - Agent questions stored with embeddings for RAG
model SkillQuestion {
  id           String     @id @default(cuid())

  // Collection relationship
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Question content
  question     String     @db.Text
  embedding    Json       @db.JsonB // Array of floats (3072 dims for text-embedding-3-large)

  // Response
  answer       String     @db.Text
  answerTokens Int        @default(0) @map("answer_tokens")

  // Agent identity (anonymized in UI)
  agentHash    String?    @map("agent_hash") @db.VarChar(64) // Hash of IP + user-agent for deduplication
  agentName    String?    @map("agent_name") @db.VarChar(100) // Self-reported agent name
  sessionId    String?    @map("session_id") // Optional session for multi-turn

  // Metadata
  tags         String[]   @default([]) @db.Text
  confidence   Float      @default(0)
  similarCount Int        @default(0) @map("similar_count") // Times similar question asked

  // Graph relationships
  skillNodes   SkillQuestionSkill[]
  toolNodes    SkillQuestionTool[]

  // Timestamps
  createdAt    DateTime   @default(now()) @map("created_at")
  updatedAt    DateTime   @updatedAt @map("updated_at")

  @@index([collectionId])
  @@index([sessionId])
  @@index([createdAt])
  @@map("skill_questions")
}

/// Skill - Emergent skill nodes identified from question patterns
model Skill {
  id           String     @id @default(cuid())

  // Collection relationship
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Skill identity
  name         String     @db.VarChar(200) // e.g., "React useEffect debugging"
  slug         String     @db.VarChar(200) // URL-safe version
  description  String     @db.Text
  embedding    Json       @db.JsonB // Array of floats (3072 dims for text-embedding-3-large)

  // Stats
  questionCount Int       @default(0) @map("question_count")
  confidence    Float     @default(0) // Aggregate confidence

  // Graph relationships
  questions     SkillQuestionSkill[]
  parentSkill   Skill?    @relation("SkillHierarchy", fields: [parentSkillId], references: [id])
  parentSkillId String?   @map("parent_skill_id")
  childSkills   Skill[]   @relation("SkillHierarchy")

  // Timestamps
  createdAt    DateTime   @default(now()) @map("created_at")
  updatedAt    DateTime   @updatedAt @map("updated_at")

  @@unique([collectionId, slug])
  @@index([collectionId])
  @@index([questionCount])
  @@map("skills")
}

/// SkillQuestionSkill - Junction table linking questions to skills
model SkillQuestionSkill {
  questionId String        @map("question_id")
  question   SkillQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
  skillId    String        @map("skill_id")
  skill      Skill         @relation(fields: [skillId], references: [id], onDelete: Cascade)
  relevance  Float         @default(1.0)

  @@id([questionId, skillId])
  @@index([questionId])
  @@index([skillId])
  @@map("skill_question_skills")
}

/// SkillQuestionTool - Junction table linking questions to tools mentioned
model SkillQuestionTool {
  questionId String        @map("question_id")
  question   SkillQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
  toolId     String        @map("tool_id")
  tool       Tool          @relation(fields: [toolId], references: [id], onDelete: Cascade)
  relevance  Float         @default(1.0)

  @@id([questionId, toolId])
  @@index([questionId])
  @@index([toolId])
  @@map("skill_question_tools")
}

/// SkillSession - Optional multi-turn conversation sessions
model SkillSession {
  id           String     @id @default(cuid())

  // Collection relationship
  collectionId String     @map("collection_id")
  collection   Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

  // Session state
  context      Json       @default("[]") @db.JsonB // Message history
  agentHash    String?    @map("agent_hash") @db.VarChar(64)
  agentName    String?    @map("agent_name") @db.VarChar(100)

  // Timestamps
  createdAt    DateTime   @default(now()) @map("created_at")
  updatedAt    DateTime   @updatedAt @map("updated_at")
  expiresAt    DateTime   @map("expires_at") // Auto-expire sessions

  @@index([collectionId])
  @@index([expiresAt])
  @@map("skill_sessions")
}
