// Mosaic Stack Database Schema
// PostgreSQL 17 with pgvector extension

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["postgresqlExtensions"]
}

datasource db {
  provider   = "postgresql"
  url        = env("DATABASE_URL")
  extensions = [pgvector(map: "vector"), uuid_ossp(map: "uuid-ossp")]
}

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

enum TaskStatus {
  NOT_STARTED
  IN_PROGRESS
  PAUSED
  COMPLETED
  ARCHIVED
}

enum TaskPriority {
  LOW
  MEDIUM
  HIGH
}

enum ProjectStatus {
  PLANNING
  ACTIVE
  PAUSED
  COMPLETED
  ARCHIVED
}

enum WorkspaceMemberRole {
  OWNER
  ADMIN
  MEMBER
  GUEST
}

enum TeamMemberRole {
  OWNER
  ADMIN
  MEMBER
}

enum ActivityAction {
  CREATED
  UPDATED
  DELETED
  COMPLETED
  ASSIGNED
  COMMENTED
  LOGIN
  LOGOUT
  PASSWORD_RESET
  EMAIL_VERIFIED
  CREDENTIAL_CREATED
  CREDENTIAL_ACCESSED
  CREDENTIAL_ROTATED
  CREDENTIAL_REVOKED
}

enum EntityType {
  TASK
  EVENT
  PROJECT
  WORKSPACE
  USER
  IDEA
  DOMAIN
  CREDENTIAL
}

enum IdeaStatus {
  CAPTURED
  PROCESSING
  ACTIONABLE
  ARCHIVED
  DISCARDED
}

enum RelationshipType {
  BLOCKS
  BLOCKED_BY
  DEPENDS_ON
  PARENT_OF
  CHILD_OF
  RELATED_TO
  DUPLICATE_OF
  SUPERSEDES
  PART_OF
}

enum AgentStatus {
  IDLE
  WORKING
  WAITING
  ERROR
  TERMINATED
}

enum AgentTaskStatus {
  PENDING
  RUNNING
  COMPLETED
  FAILED
}

enum AgentTaskPriority {
  LOW
  MEDIUM
  HIGH
}

enum EntryStatus {
  DRAFT
  PUBLISHED
  ARCHIVED
}

enum Visibility {
  PRIVATE
  WORKSPACE
  PUBLIC
}

enum FormalityLevel {
  VERY_CASUAL
  CASUAL
  NEUTRAL
  FORMAL
  VERY_FORMAL
}

enum RunnerJobStatus {
  PENDING
  QUEUED
  RUNNING
  COMPLETED
  FAILED
  CANCELLED
}

enum JobStepPhase {
  SETUP
  EXECUTION
  VALIDATION
  CLEANUP
}

enum JobStepType {
  COMMAND
  AI_ACTION
  GATE
  ARTIFACT
}

enum JobStepStatus {
  PENDING
  RUNNING
  COMPLETED
  FAILED
  SKIPPED
}

enum FederationConnectionStatus {
  PENDING
  ACTIVE
  SUSPENDED
  DISCONNECTED
}

enum FederationMessageType {
  QUERY
  COMMAND
  EVENT
}

enum FederationMessageStatus {
  PENDING
  DELIVERED
  FAILED
  TIMEOUT
}

enum CredentialType {
  API_KEY
  OAUTH_TOKEN
  ACCESS_TOKEN
  SECRET
  PASSWORD
  CUSTOM
}

enum CredentialScope {
  USER
  WORKSPACE
  SYSTEM
}

// ============================================
// MODELS
// ============================================

model User {
  id             String   @id @default(uuid()) @db.Uuid
  email          String   @unique
  name           String
  emailVerified  Boolean  @default(false) @map("email_verified")
  image          String?
  authProviderId String?  @unique @map("auth_provider_id")
  preferences    Json     @default("{}")
  createdAt      DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt      DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  ownedWorkspaces        Workspace[]             @relation("WorkspaceOwner")
  workspaceMemberships   WorkspaceMember[]
  teamMemberships        TeamMember[]
  assignedTasks          Task[]                  @relation("TaskAssignee")
  createdTasks           Task[]                  @relation("TaskCreator")
  createdEvents          Event[]                 @relation("EventCreator")
  createdProjects        Project[]               @relation("ProjectCreator")
  activityLogs           ActivityLog[]
  sessions               Session[]
  accounts               Account[]
  ideas                  Idea[]                  @relation("IdeaCreator")
  relationships          Relationship[]          @relation("RelationshipCreator")
  agentSessions          AgentSession[]
  agentTasks             AgentTask[]             @relation("AgentTaskCreator")
  userLayouts            UserLayout[]
  userPreference         UserPreference?
  knowledgeEntryVersions KnowledgeEntryVersion[] @relation("EntryVersionAuthor")
  llmProviders           LlmProviderInstance[]   @relation("UserLlmProviders")
  federatedIdentities    FederatedIdentity[]
  llmUsageLogs           LlmUsageLog[]           @relation("UserLlmUsageLogs")
  userCredentials        UserCredential[]        @relation("UserCredentials")

  @@map("users")
}

model UserPreference {
  id        String   @id @default(uuid()) @db.Uuid
  userId    String   @unique @map("user_id") @db.Uuid
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  theme     String   @default("system")
  locale    String   @default("en")
  timezone  String?
  settings  Json     @default("{}")
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  @@map("user_preferences")
}

model Workspace {
  id        String   @id @default(uuid()) @db.Uuid
  name      String
  ownerId   String   @map("owner_id") @db.Uuid
  settings  Json     @default("{}")
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  owner                        User                          @relation("WorkspaceOwner", fields: [ownerId], references: [id], onDelete: Cascade)
  members                      WorkspaceMember[]
  teams                        Team[]
  tasks                        Task[]
  events                       Event[]
  projects                     Project[]
  activityLogs                 ActivityLog[]
  memoryEmbeddings             MemoryEmbedding[]
  domains                      Domain[]
  ideas                        Idea[]
  relationships                Relationship[]
  agents                       Agent[]
  agentSessions                AgentSession[]
  agentTasks                   AgentTask[]
  userLayouts                  UserLayout[]
  knowledgeEntries             KnowledgeEntry[]
  knowledgeTags                KnowledgeTag[]
  cronSchedules                CronSchedule[]
  personalities                Personality[]
  llmSettings                  WorkspaceLlmSettings?
  qualityGates                 QualityGate[]
  runnerJobs                   RunnerJob[]
  federationConnections        FederationConnection[]
  federationMessages           FederationMessage[]
  federationEventSubscriptions FederationEventSubscription[]
  llmUsageLogs                 LlmUsageLog[]
  userCredentials              UserCredential[]

  @@index([ownerId])
  @@map("workspaces")
}

model WorkspaceMember {
  workspaceId String              @map("workspace_id") @db.Uuid
  userId      String              @map("user_id") @db.Uuid
  role        WorkspaceMemberRole @default(MEMBER)
  joinedAt    DateTime            @default(now()) @map("joined_at") @db.Timestamptz

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

  @@id([workspaceId, userId])
  @@index([userId])
  @@map("workspace_members")
}

model Team {
  id          String   @id @default(uuid()) @db.Uuid
  workspaceId String   @map("workspace_id") @db.Uuid
  name        String
  description String?  @db.Text
  metadata    Json     @default("{}")
  createdAt   DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  workspace Workspace    @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  members   TeamMember[]

  @@index([workspaceId])
  @@map("teams")
}

model TeamMember {
  teamId   String         @map("team_id") @db.Uuid
  userId   String         @map("user_id") @db.Uuid
  role     TeamMemberRole @default(MEMBER)
  joinedAt DateTime       @default(now()) @map("joined_at") @db.Timestamptz

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

  @@id([teamId, userId])
  @@index([userId])
  @@map("team_members")
}

model Task {
  id          String       @id @default(uuid()) @db.Uuid
  workspaceId String       @map("workspace_id") @db.Uuid
  title       String
  description String?      @db.Text
  status      TaskStatus   @default(NOT_STARTED)
  priority    TaskPriority @default(MEDIUM)
  dueDate     DateTime?    @map("due_date") @db.Timestamptz
  assigneeId  String?      @map("assignee_id") @db.Uuid
  creatorId   String       @map("creator_id") @db.Uuid
  projectId   String?      @map("project_id") @db.Uuid
  parentId    String?      @map("parent_id") @db.Uuid
  domainId    String?      @map("domain_id") @db.Uuid
  sortOrder   Int          @default(0) @map("sort_order")
  metadata    Json         @default("{}")
  createdAt   DateTime     @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime     @updatedAt @map("updated_at") @db.Timestamptz
  completedAt DateTime?    @map("completed_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  assignee  User?     @relation("TaskAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
  creator   User      @relation("TaskCreator", fields: [creatorId], references: [id], onDelete: Cascade)
  project   Project?  @relation(fields: [projectId], references: [id], onDelete: SetNull)
  parent    Task?     @relation("TaskSubtasks", fields: [parentId], references: [id], onDelete: Cascade)
  subtasks  Task[]    @relation("TaskSubtasks")
  domain    Domain?   @relation(fields: [domainId], references: [id], onDelete: SetNull)

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([workspaceId, dueDate])
  @@index([assigneeId])
  @@index([projectId])
  @@index([parentId])
  @@index([domainId])
  @@map("tasks")
}

model Event {
  id          String    @id @default(uuid()) @db.Uuid
  workspaceId String    @map("workspace_id") @db.Uuid
  title       String
  description String?   @db.Text
  startTime   DateTime  @map("start_time") @db.Timestamptz
  endTime     DateTime? @map("end_time") @db.Timestamptz
  allDay      Boolean   @default(false) @map("all_day")
  location    String?
  recurrence  Json?
  creatorId   String    @map("creator_id") @db.Uuid
  projectId   String?   @map("project_id") @db.Uuid
  domainId    String?   @map("domain_id") @db.Uuid
  metadata    Json      @default("{}")
  createdAt   DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime  @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  creator   User      @relation("EventCreator", fields: [creatorId], references: [id], onDelete: Cascade)
  project   Project?  @relation(fields: [projectId], references: [id], onDelete: SetNull)
  domain    Domain?   @relation(fields: [domainId], references: [id], onDelete: SetNull)

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, startTime])
  @@index([creatorId])
  @@index([projectId])
  @@index([domainId])
  @@map("events")
}

model Project {
  id          String        @id @default(uuid()) @db.Uuid
  workspaceId String        @map("workspace_id") @db.Uuid
  name        String
  description String?       @db.Text
  status      ProjectStatus @default(PLANNING)
  startDate   DateTime?     @map("start_date") @db.Date
  endDate     DateTime?     @map("end_date") @db.Date
  creatorId   String        @map("creator_id") @db.Uuid
  domainId    String?       @map("domain_id") @db.Uuid
  color       String?
  metadata    Json          @default("{}")
  createdAt   DateTime      @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime      @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  creator   User      @relation("ProjectCreator", fields: [creatorId], references: [id], onDelete: Cascade)
  tasks     Task[]
  events    Event[]
  domain    Domain?   @relation(fields: [domainId], references: [id], onDelete: SetNull)
  ideas     Idea[]

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([creatorId])
  @@index([domainId])
  @@map("projects")
}

model ActivityLog {
  id          String         @id @default(uuid()) @db.Uuid
  workspaceId String         @map("workspace_id") @db.Uuid
  userId      String         @map("user_id") @db.Uuid
  action      ActivityAction
  entityType  EntityType     @map("entity_type")
  entityId    String         @map("entity_id") @db.Uuid
  details     Json           @default("{}")
  ipAddress   String?        @map("ip_address")
  userAgent   String?        @map("user_agent")
  createdAt   DateTime       @default(now()) @map("created_at") @db.Timestamptz

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

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, createdAt])
  @@index([entityType, entityId])
  @@index([userId])
  @@index([action])
  @@map("activity_logs")
}

model MemoryEmbedding {
  id          String                       @id @default(uuid()) @db.Uuid
  workspaceId String                       @map("workspace_id") @db.Uuid
  content     String                       @db.Text
  // Note: vector dimension (1536) must match EMBEDDING_DIMENSION constant in @mosaic/shared
  embedding   Unsupported("vector(1536)")?
  entityType  EntityType?                  @map("entity_type")
  entityId    String?                      @map("entity_id") @db.Uuid
  metadata    Json                         @default("{}")
  createdAt   DateTime                     @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime                     @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  @@index([workspaceId])
  @@map("memory_embeddings")
}

// ============================================
// NEW MODELS
// ============================================

model Domain {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid

  name        String
  slug        String
  description String? @db.Text
  color       String?
  icon        String?
  sortOrder   Int     @default(0) @map("sort_order")

  metadata Json @default("{}")

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

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  tasks     Task[]
  events    Event[]
  projects  Project[]
  ideas     Idea[]

  @@unique([id, workspaceId])
  @@unique([workspaceId, slug])
  @@index([workspaceId])
  @@map("domains")
}

model Idea {
  id          String  @id @default(uuid()) @db.Uuid
  workspaceId String  @map("workspace_id") @db.Uuid
  domainId    String? @map("domain_id") @db.Uuid
  projectId   String? @map("project_id") @db.Uuid

  // Core fields
  title   String?
  content String  @db.Text

  // Status
  status   IdeaStatus   @default(CAPTURED)
  priority TaskPriority @default(MEDIUM)

  // Categorization
  category String?
  tags     String[]

  metadata Json @default("{}")

  // Embedding for semantic search (pgvector)
  embedding Unsupported("vector(1536)")?

  // Audit
  creatorId String   @map("creator_id") @db.Uuid
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  domain    Domain?   @relation(fields: [domainId], references: [id], onDelete: SetNull)
  project   Project?  @relation(fields: [projectId], references: [id], onDelete: SetNull)
  creator   User      @relation("IdeaCreator", fields: [creatorId], references: [id], onDelete: Cascade)

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([domainId])
  @@index([projectId])
  @@index([creatorId])
  @@map("ideas")
}

model Relationship {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid

  // Source entity
  sourceType EntityType @map("source_type")
  sourceId   String     @map("source_id") @db.Uuid

  // Target entity
  targetType EntityType @map("target_type")
  targetId   String     @map("target_id") @db.Uuid

  // Relationship type
  relationship RelationshipType

  metadata Json    @default("{}")
  notes    String? @db.Text

  // Audit
  creatorId String   @map("creator_id") @db.Uuid
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  creator   User      @relation("RelationshipCreator", fields: [creatorId], references: [id], onDelete: Cascade)

  // Prevent duplicate relationships
  @@unique([workspaceId, sourceType, sourceId, targetType, targetId, relationship])
  @@index([sourceType, sourceId])
  @@index([targetType, targetId])
  @@index([relationship])
  @@map("relationships")
}

model Agent {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid

  // Identity
  agentId String  @map("agent_id")
  name    String?
  model   String?
  role    String?

  // Status
  status      AgentStatus @default(IDLE)
  currentTask String?     @map("current_task") @db.Text

  // Performance metrics
  metrics Json @default("{\"totalTasks\": 0, \"successfulTasks\": 0, \"failedTasks\": 0, \"avgResponseTimeMs\": 0}")

  // Health
  lastHeartbeat DateTime? @map("last_heartbeat") @db.Timestamptz
  errorCount    Int       @default(0) @map("error_count")
  lastError     String?   @map("last_error") @db.Text

  // Firing history
  firedCount  Int  @default(0) @map("fired_count")
  fireHistory Json @default("[]") @map("fire_history")

  createdAt    DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt    DateTime  @updatedAt @map("updated_at") @db.Timestamptz
  terminatedAt DateTime? @map("terminated_at") @db.Timestamptz

  // Relations
  workspace Workspace      @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  sessions  AgentSession[]

  @@unique([workspaceId, agentId])
  @@index([workspaceId])
  @@index([status])
  @@map("agents")
}

model AgentTask {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid

  // Task details
  title       String
  description String?           @db.Text
  status      AgentTaskStatus   @default(PENDING)
  priority    AgentTaskPriority @default(MEDIUM)

  // Agent configuration
  agentType   String @map("agent_type")
  agentConfig Json   @default("{}") @map("agent_config")

  // Results
  result Json?
  error  String? @db.Text

  // Timing
  createdAt   DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime  @updatedAt @map("updated_at") @db.Timestamptz
  startedAt   DateTime? @map("started_at") @db.Timestamptz
  completedAt DateTime? @map("completed_at") @db.Timestamptz

  // Relations
  workspace   Workspace   @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  createdBy   User        @relation("AgentTaskCreator", fields: [createdById], references: [id], onDelete: Cascade)
  createdById String      @map("created_by_id") @db.Uuid
  runnerJobs  RunnerJob[]

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([createdById])
  @@index([agentType])
  @@map("agent_tasks")
}

model AgentSession {
  id          String  @id @default(uuid()) @db.Uuid
  workspaceId String  @map("workspace_id") @db.Uuid
  userId      String  @map("user_id") @db.Uuid
  agentId     String? @map("agent_id") @db.Uuid

  // Identity
  sessionKey String  @map("session_key")
  label      String?
  channel    String?

  // Context
  contextSummary String? @map("context_summary") @db.Text
  messageCount   Int     @default(0) @map("message_count")

  // Status
  isActive Boolean @default(true) @map("is_active")

  startedAt     DateTime  @default(now()) @map("started_at") @db.Timestamptz
  lastMessageAt DateTime? @map("last_message_at") @db.Timestamptz
  endedAt       DateTime? @map("ended_at") @db.Timestamptz

  metadata Json @default("{}")

  // Relations
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  user      User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  agent     Agent?    @relation(fields: [agentId], references: [id], onDelete: SetNull)

  @@unique([workspaceId, sessionKey])
  @@index([workspaceId])
  @@index([userId])
  @@index([agentId])
  @@index([isActive])
  @@map("agent_sessions")
}

model WidgetDefinition {
  id String @id @default(uuid()) @db.Uuid

  name        String  @unique
  displayName String  @map("display_name")
  description String? @db.Text
  component   String

  // Default size (grid units)
  defaultWidth  Int  @default(1) @map("default_width")
  defaultHeight Int  @default(1) @map("default_height")
  minWidth      Int  @default(1) @map("min_width")
  minHeight     Int  @default(1) @map("min_height")
  maxWidth      Int? @map("max_width")
  maxHeight     Int? @map("max_height")

  // Configuration schema (JSON Schema for widget config)
  configSchema Json @default("{}") @map("config_schema")

  isActive  Boolean  @default(true) @map("is_active")
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz

  @@map("widget_definitions")
}

model UserLayout {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid
  userId      String @map("user_id") @db.Uuid

  name      String
  isDefault Boolean @default(false) @map("is_default")

  // Layout configuration (array of widget placements)
  layout Json @default("[]")

  // Additional metadata for the layout
  metadata Json @default("{}")

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

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

  @@unique([id, workspaceId])
  @@unique([workspaceId, userId, name])
  @@index([userId])
  @@map("user_layouts")
}

// ============================================
// AUTHENTICATION MODELS (BetterAuth)
// ============================================

model Session {
  id        String   @id @default(uuid()) @db.Uuid
  userId    String   @map("user_id") @db.Uuid
  token     String   @unique
  expiresAt DateTime @map("expires_at") @db.Timestamptz
  ipAddress String?  @map("ip_address")
  userAgent String?  @map("user_agent")
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

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

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

model Account {
  id                    String    @id @default(uuid()) @db.Uuid
  userId                String    @map("user_id") @db.Uuid
  accountId             String    @map("account_id")
  providerId            String    @map("provider_id")
  accessToken           String?   @map("access_token")
  refreshToken          String?   @map("refresh_token")
  idToken               String?   @map("id_token")
  accessTokenExpiresAt  DateTime? @map("access_token_expires_at") @db.Timestamptz
  refreshTokenExpiresAt DateTime? @map("refresh_token_expires_at") @db.Timestamptz
  scope                 String?
  password              String?
  encryptionVersion     String?   @map("encryption_version") @db.VarChar(20)
  createdAt             DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt             DateTime  @updatedAt @map("updated_at") @db.Timestamptz

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

  @@unique([providerId, accountId])
  @@index([userId])
  @@index([encryptionVersion])
  @@map("accounts")
}

model Verification {
  id         String   @id @default(uuid()) @db.Uuid
  identifier String
  value      String
  expiresAt  DateTime @map("expires_at") @db.Timestamptz
  createdAt  DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt  DateTime @updatedAt @map("updated_at") @db.Timestamptz

  @@index([identifier])
  @@map("verifications")
}

// ============================================
// USER CREDENTIALS MODULE
// ============================================

model UserCredential {
  id          String  @id @default(uuid()) @db.Uuid
  userId      String  @map("user_id") @db.Uuid
  workspaceId String? @map("workspace_id") @db.Uuid

  // Identity
  name     String
  provider String // "github", "openai", "custom"
  type     CredentialType
  scope    CredentialScope @default(USER)

  // Encrypted storage
  encryptedValue String  @map("encrypted_value") @db.Text
  maskedValue    String? @map("masked_value") @db.VarChar(20)

  // Metadata
  description String?   @db.Text
  expiresAt   DateTime? @map("expires_at") @db.Timestamptz
  lastUsedAt  DateTime? @map("last_used_at") @db.Timestamptz
  metadata    Json      @default("{}")

  // Status
  isActive  Boolean   @default(true) @map("is_active")
  rotatedAt DateTime? @map("rotated_at") @db.Timestamptz

  // Audit
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  user      User       @relation("UserCredentials", fields: [userId], references: [id], onDelete: Cascade)
  workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  @@unique([userId, workspaceId, provider, name])
  @@index([userId])
  @@index([workspaceId])
  @@index([userId, scope])
  @@index([workspaceId, scope])
  @@index([scope, isActive])
  @@map("user_credentials")
}

// ============================================
// KNOWLEDGE MODULE
// ============================================

model KnowledgeEntry {
  id          String    @id @default(uuid()) @db.Uuid
  workspaceId String    @map("workspace_id") @db.Uuid
  workspace   Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  // Identity
  slug  String
  title String

  // Content
  content     String  @db.Text
  contentHtml String? @map("content_html") @db.Text
  summary     String?

  // Full-text search vector (automatically maintained by trigger)
  searchVector Unsupported("tsvector")? @map("search_vector")

  // Status
  status     EntryStatus @default(DRAFT)
  visibility Visibility  @default(PRIVATE)

  // Audit
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
  createdBy String   @map("created_by") @db.Uuid
  updatedBy String   @map("updated_by") @db.Uuid

  // Relations
  tags          KnowledgeEntryTag[]
  outgoingLinks KnowledgeLink[]         @relation("SourceEntry")
  incomingLinks KnowledgeLink[]         @relation("TargetEntry")
  versions      KnowledgeEntryVersion[]
  embedding     KnowledgeEmbedding?

  @@unique([workspaceId, slug])
  @@index([workspaceId, status])
  @@index([workspaceId, updatedAt])
  @@index([createdBy])
  @@index([updatedBy])
  // Note: GIN index on searchVector created via migration (not supported in Prisma schema)
  @@map("knowledge_entries")
}

model KnowledgeEntryVersion {
  id      String         @id @default(uuid()) @db.Uuid
  entryId String         @map("entry_id") @db.Uuid
  entry   KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)

  version Int
  title   String
  content String  @db.Text
  summary String?

  createdAt  DateTime @default(now()) @map("created_at") @db.Timestamptz
  createdBy  String   @map("created_by") @db.Uuid
  author     User     @relation("EntryVersionAuthor", fields: [createdBy], references: [id])
  changeNote String?  @map("change_note")

  @@unique([entryId, version])
  @@index([entryId, version])
  @@map("knowledge_entry_versions")
}

model KnowledgeLink {
  id String @id @default(uuid()) @db.Uuid

  sourceId String         @map("source_id") @db.Uuid
  source   KnowledgeEntry @relation("SourceEntry", fields: [sourceId], references: [id], onDelete: Cascade)

  targetId String         @map("target_id") @db.Uuid
  target   KnowledgeEntry @relation("TargetEntry", fields: [targetId], references: [id], onDelete: Cascade)

  // Link metadata
  linkText    String  @map("link_text")
  displayText String  @map("display_text")
  context     String?

  // Position in source content
  positionStart Int @map("position_start")
  positionEnd   Int @map("position_end")

  // Resolution status
  resolved Boolean @default(true)

  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz

  @@unique([sourceId, targetId])
  @@index([sourceId])
  @@index([targetId])
  @@index([resolved])
  @@map("knowledge_links")
}

model KnowledgeTag {
  id          String    @id @default(uuid()) @db.Uuid
  workspaceId String    @map("workspace_id") @db.Uuid
  workspace   Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  name        String
  slug        String
  color       String?
  description String?

  entries KnowledgeEntryTag[]

  @@unique([workspaceId, slug])
  @@index([workspaceId])
  @@map("knowledge_tags")
}

model KnowledgeEntryTag {
  entryId String         @map("entry_id") @db.Uuid
  entry   KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)

  tagId String       @map("tag_id") @db.Uuid
  tag   KnowledgeTag @relation(fields: [tagId], references: [id], onDelete: Cascade)

  @@id([entryId, tagId])
  @@index([entryId])
  @@index([tagId])
  @@map("knowledge_entry_tags")
}

model KnowledgeEmbedding {
  id      String         @id @default(uuid()) @db.Uuid
  entryId String         @unique @map("entry_id") @db.Uuid
  entry   KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)

  embedding Unsupported("vector(1536)")
  model     String

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

  @@index([entryId])
  @@map("knowledge_embeddings")
}

// ============================================
// CRON JOBS
// ============================================

model CronSchedule {
  id          String    @id @default(uuid()) @db.Uuid
  workspaceId String    @map("workspace_id") @db.Uuid
  workspace   Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  // Cron configuration
  expression String // Standard cron: "0 9 * * *" = 9am daily
  command    String // MoltBot command to trigger

  // State
  enabled Boolean   @default(true)
  lastRun DateTime? @map("last_run") @db.Timestamptz
  nextRun DateTime? @map("next_run") @db.Timestamptz

  // Audit
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  @@index([workspaceId])
  @@index([workspaceId, enabled])
  @@index([nextRun])
  @@map("cron_schedules")
}

// ============================================
// PERSONALITY MODULE
// ============================================

model Personality {
  id          String    @id @default(uuid()) @db.Uuid
  workspaceId String    @map("workspace_id") @db.Uuid
  workspace   Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  // Identity
  name        String // unique identifier slug
  displayName String  @map("display_name")
  description String? @db.Text

  // System prompt
  systemPrompt String @map("system_prompt") @db.Text

  // LLM configuration
  temperature           Float? // null = use provider default
  maxTokens             Int?    @map("max_tokens") // null = use provider default
  llmProviderInstanceId String? @map("llm_provider_instance_id") @db.Uuid

  // Status
  isDefault Boolean @default(false) @map("is_default")
  isEnabled Boolean @default(true) @map("is_enabled")

  // Audit
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  llmProviderInstance  LlmProviderInstance?   @relation("PersonalityLlmProvider", fields: [llmProviderInstanceId], references: [id], onDelete: SetNull)
  workspaceLlmSettings WorkspaceLlmSettings[] @relation("WorkspacePersonality")

  @@unique([id, workspaceId])
  @@unique([workspaceId, name])
  @@index([workspaceId])
  @@index([workspaceId, isDefault])
  @@index([workspaceId, isEnabled])
  @@index([llmProviderInstanceId])
  @@map("personalities")
}

// ============================================
// LLM PROVIDER MODULE
// ============================================

model LlmProviderInstance {
  id           String   @id @default(uuid()) @db.Uuid
  providerType String   @map("provider_type") // "ollama" | "claude" | "openai"
  displayName  String   @map("display_name")
  userId       String?  @map("user_id") @db.Uuid // NULL = system-level, UUID = user-level
  config       Json // Provider-specific configuration
  isDefault    Boolean  @default(false) @map("is_default")
  isEnabled    Boolean  @default(true) @map("is_enabled")
  createdAt    DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt    DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  user                 User?                  @relation("UserLlmProviders", fields: [userId], references: [id], onDelete: Cascade)
  personalities        Personality[]          @relation("PersonalityLlmProvider")
  workspaceLlmSettings WorkspaceLlmSettings[] @relation("WorkspaceLlmProvider")
  llmUsageLogs         LlmUsageLog[]          @relation("LlmUsageLogs")

  @@index([userId])
  @@index([providerType])
  @@index([isDefault])
  @@index([isEnabled])
  @@map("llm_provider_instances")
}

// ============================================
// WORKSPACE LLM SETTINGS
// ============================================

model WorkspaceLlmSettings {
  id                   String               @id @default(uuid()) @db.Uuid
  workspaceId          String               @unique @map("workspace_id") @db.Uuid
  workspace            Workspace            @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  defaultLlmProviderId String?              @map("default_llm_provider_id") @db.Uuid
  defaultLlmProvider   LlmProviderInstance? @relation("WorkspaceLlmProvider", fields: [defaultLlmProviderId], references: [id], onDelete: SetNull)
  defaultPersonalityId String?              @map("default_personality_id") @db.Uuid
  defaultPersonality   Personality?         @relation("WorkspacePersonality", fields: [defaultPersonalityId], references: [id], onDelete: SetNull)
  settings             Json?                @default("{}")
  createdAt            DateTime             @default(now()) @map("created_at") @db.Timestamptz
  updatedAt            DateTime             @updatedAt @map("updated_at") @db.Timestamptz

  @@index([workspaceId])
  @@index([defaultLlmProviderId])
  @@index([defaultPersonalityId])
  @@map("workspace_llm_settings")
}

// ============================================
// QUALITY GATE MODULE
// ============================================

model QualityGate {
  id             String    @id @default(uuid()) @db.Uuid
  workspaceId    String    @map("workspace_id") @db.Uuid
  workspace      Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  name           String
  description    String?
  type           String // 'build' | 'lint' | 'test' | 'coverage' | 'custom'
  command        String?
  expectedOutput String?   @map("expected_output")
  isRegex        Boolean   @default(false) @map("is_regex")
  required       Boolean   @default(true)
  order          Int       @default(0)
  isEnabled      Boolean   @default(true) @map("is_enabled")
  createdAt      DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt      DateTime  @updatedAt @map("updated_at") @db.Timestamptz

  @@unique([workspaceId, name])
  @@index([workspaceId])
  @@index([workspaceId, isEnabled])
  @@map("quality_gates")
}

model TaskRejection {
  id           String    @id @default(uuid()) @db.Uuid
  taskId       String    @map("task_id")
  workspaceId  String    @map("workspace_id")
  agentId      String    @map("agent_id")
  attemptCount Int       @map("attempt_count")
  failures     Json // FailureSummary[]
  originalTask String    @map("original_task")
  startedAt    DateTime  @map("started_at") @db.Timestamptz
  rejectedAt   DateTime  @map("rejected_at") @db.Timestamptz
  escalated    Boolean   @default(false)
  manualReview Boolean   @default(false) @map("manual_review")
  resolvedAt   DateTime? @map("resolved_at") @db.Timestamptz
  resolution   String?

  @@index([taskId])
  @@index([workspaceId])
  @@index([agentId])
  @@index([escalated])
  @@index([manualReview])
  @@map("task_rejections")
}

model TokenBudget {
  id          String @id @default(uuid()) @db.Uuid
  taskId      String @unique @map("task_id") @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid
  agentId     String @map("agent_id")

  // Budget allocation
  allocatedTokens     Int    @map("allocated_tokens")
  estimatedComplexity String @map("estimated_complexity") // "low", "medium", "high", "critical"

  // Usage tracking
  inputTokensUsed  Int @default(0) @map("input_tokens_used")
  outputTokensUsed Int @default(0) @map("output_tokens_used")
  totalTokensUsed  Int @default(0) @map("total_tokens_used")

  // Cost tracking
  estimatedCost Decimal? @map("estimated_cost") @db.Decimal(10, 6)

  // State
  startedAt     DateTime  @default(now()) @map("started_at") @db.Timestamptz
  lastUpdatedAt DateTime  @updatedAt @map("last_updated_at") @db.Timestamptz
  completedAt   DateTime? @map("completed_at") @db.Timestamptz

  // Analysis
  budgetUtilization Float?  @map("budget_utilization") // 0.0 - 1.0
  suspiciousPattern Boolean @default(false) @map("suspicious_pattern")
  suspiciousReason  String? @map("suspicious_reason")

  @@index([taskId])
  @@index([workspaceId])
  @@index([suspiciousPattern])
  @@map("token_budgets")
}

// ============================================
// RUNNER JOB TRACKING MODULE
// ============================================

model RunnerJob {
  id          String  @id @default(uuid()) @db.Uuid
  workspaceId String  @map("workspace_id") @db.Uuid
  agentTaskId String? @map("agent_task_id") @db.Uuid

  // Job details
  type            String // 'git-status', 'code-task', 'priority-calc'
  status          RunnerJobStatus @default(PENDING)
  priority        Int
  progressPercent Int             @default(0) @map("progress_percent")
  version         Int             @default(1) // Optimistic locking version

  // Results
  result Json?
  error  String? @db.Text

  // Timing
  createdAt   DateTime  @default(now()) @map("created_at") @db.Timestamptz
  startedAt   DateTime? @map("started_at") @db.Timestamptz
  completedAt DateTime? @map("completed_at") @db.Timestamptz

  // Relations
  workspace Workspace  @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  agentTask AgentTask? @relation(fields: [agentTaskId], references: [id], onDelete: SetNull)
  steps     JobStep[]
  events    JobEvent[]

  @@unique([id, workspaceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([agentTaskId])
  @@index([priority])
  @@map("runner_jobs")
}

model JobStep {
  id    String @id @default(uuid()) @db.Uuid
  jobId String @map("job_id") @db.Uuid

  // Step details
  ordinal Int
  phase   JobStepPhase
  name    String
  type    JobStepType
  status  JobStepStatus @default(PENDING)

  // Output and metrics
  output       String? @db.Text
  tokensInput  Int?    @map("tokens_input")
  tokensOutput Int?    @map("tokens_output")

  // Timing
  startedAt   DateTime? @map("started_at") @db.Timestamptz
  completedAt DateTime? @map("completed_at") @db.Timestamptz
  durationMs  Int?      @map("duration_ms")

  // Relations
  job    RunnerJob  @relation(fields: [jobId], references: [id], onDelete: Cascade)
  events JobEvent[]

  @@index([jobId])
  @@index([jobId, ordinal])
  @@index([status])
  @@map("job_steps")
}

model JobEvent {
  id     String  @id @default(uuid()) @db.Uuid
  jobId  String  @map("job_id") @db.Uuid
  stepId String? @map("step_id") @db.Uuid

  // Event details
  type      String
  timestamp DateTime @db.Timestamptz
  actor     String
  payload   Json

  // Relations
  job  RunnerJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
  step JobStep?  @relation(fields: [stepId], references: [id], onDelete: Cascade)

  @@index([jobId])
  @@index([stepId])
  @@index([timestamp])
  @@index([type])
  @@index([jobId, timestamp])
  @@map("job_events")
}

// ============================================
// FEDERATION MODULE
// ============================================

model Instance {
  id         String @id @default(uuid()) @db.Uuid
  instanceId String @unique @map("instance_id") // Unique identifier for federation
  name       String
  url        String
  publicKey  String @map("public_key") @db.Text
  privateKey String @map("private_key") @db.Text // AES-256-GCM encrypted with ENCRYPTION_KEY

  // Capabilities and metadata
  capabilities Json @default("{}")
  metadata     Json @default("{}")

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

  @@map("instances")
}

model FederationConnection {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid

  // Remote instance details
  remoteInstanceId   String @map("remote_instance_id")
  remoteUrl          String @map("remote_url")
  remotePublicKey    String @map("remote_public_key") @db.Text
  remoteCapabilities Json   @default("{}") @map("remote_capabilities")

  // Connection status
  status FederationConnectionStatus @default(PENDING)

  // Metadata
  metadata Json @default("{}")

  // Timestamps
  createdAt      DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt      DateTime  @updatedAt @map("updated_at") @db.Timestamptz
  connectedAt    DateTime? @map("connected_at") @db.Timestamptz
  disconnectedAt DateTime? @map("disconnected_at") @db.Timestamptz

  // Relations
  workspace          Workspace                     @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  messages           FederationMessage[]
  eventSubscriptions FederationEventSubscription[]

  @@unique([workspaceId, remoteInstanceId])
  @@index([workspaceId])
  @@index([workspaceId, status])
  @@index([remoteInstanceId])
  @@map("federation_connections")
}

model FederatedIdentity {
  id               String   @id @default(uuid()) @db.Uuid
  localUserId      String   @map("local_user_id") @db.Uuid
  remoteUserId     String   @map("remote_user_id")
  remoteInstanceId String   @map("remote_instance_id")
  oidcSubject      String   @map("oidc_subject")
  email            String
  metadata         Json     @default("{}")
  createdAt        DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt        DateTime @updatedAt @map("updated_at") @db.Timestamptz

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

  @@unique([localUserId, remoteInstanceId])
  @@index([localUserId])
  @@index([remoteInstanceId])
  @@index([oidcSubject])
  @@map("federated_identities")
}

model FederationMessage {
  id           String @id @default(uuid()) @db.Uuid
  workspaceId  String @map("workspace_id") @db.Uuid
  connectionId String @map("connection_id") @db.Uuid

  // Message metadata
  messageType   FederationMessageType @map("message_type")
  messageId     String                @unique @map("message_id") // UUID for deduplication
  correlationId String?               @map("correlation_id") // For request/response tracking

  // Message content
  query       String? @db.Text
  commandType String? @map("command_type") @db.Text
  eventType   String? @map("event_type") @db.Text // For EVENT messages
  payload     Json?   @default("{}")
  response    Json?   @default("{}")

  // Status tracking
  status FederationMessageStatus @default(PENDING)
  error  String?                 @db.Text

  // Security
  signature String @db.Text

  // Timestamps
  createdAt   DateTime  @default(now()) @map("created_at") @db.Timestamptz
  updatedAt   DateTime  @updatedAt @map("updated_at") @db.Timestamptz
  deliveredAt DateTime? @map("delivered_at") @db.Timestamptz

  // Relations
  connection FederationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  workspace  Workspace            @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  @@index([workspaceId])
  @@index([connectionId])
  @@index([messageId])
  @@index([correlationId])
  @@index([eventType])
  @@map("federation_messages")
}

model FederationEventSubscription {
  id           String @id @default(uuid()) @db.Uuid
  workspaceId  String @map("workspace_id") @db.Uuid
  connectionId String @map("connection_id") @db.Uuid

  // Event subscription details
  eventType String   @map("event_type")
  metadata  Json     @default("{}")
  isActive  Boolean  @default(true) @map("is_active")
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz

  // Relations
  connection FederationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
  workspace  Workspace            @relation(fields: [workspaceId], references: [id], onDelete: Cascade)

  @@unique([workspaceId, connectionId, eventType])
  @@index([workspaceId])
  @@index([connectionId])
  @@index([eventType])
  @@index([workspaceId, isActive])
  @@map("federation_event_subscriptions")
}

// ============================================
// LLM USAGE TRACKING MODULE
// ============================================

model LlmUsageLog {
  id          String @id @default(uuid()) @db.Uuid
  workspaceId String @map("workspace_id") @db.Uuid
  userId      String @map("user_id") @db.Uuid

  // LLM provider and model info
  provider           String  @db.VarChar(50)
  model              String  @db.VarChar(100)
  providerInstanceId String? @map("provider_instance_id") @db.Uuid

  // Token usage
  promptTokens     Int @default(0) @map("prompt_tokens")
  completionTokens Int @default(0) @map("completion_tokens")
  totalTokens      Int @default(0) @map("total_tokens")

  // Optional cost (in cents for precision)
  costCents Float? @map("cost_cents")

  // Task type for routing analytics
  taskType String? @map("task_type") @db.VarChar(50)

  // Optional reference to conversation/session
  conversationId String? @map("conversation_id") @db.Uuid

  // Duration in milliseconds
  durationMs Int? @map("duration_ms")

  // Timestamp
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz

  // Relations
  workspace           Workspace            @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
  user                User                 @relation("UserLlmUsageLogs", fields: [userId], references: [id], onDelete: Cascade)
  llmProviderInstance LlmProviderInstance? @relation("LlmUsageLogs", fields: [providerInstanceId], references: [id], onDelete: SetNull)

  @@index([workspaceId])
  @@index([workspaceId, createdAt])
  @@index([userId])
  @@index([provider])
  @@index([model])
  @@index([providerInstanceId])
  @@index([taskType])
  @@index([conversationId])
  @@map("llm_usage_logs")
}
