datasource db {
  provider = "sqlite"
}

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

// Workflow orchestration models
model WorkflowDefinition {
  id          String    @id @default(cuid())
  project_id  String // Project ID (required)
  identifier  String // Workflow identifier from code definition (e.g., "example-text-workflow")
  name        String // Display name (e.g., "Example Text Workflow")
  description String?
  type        String // 'code' or 'yaml'
  path        String // Filesystem path to template
  phases      Json // Array of phase names: ["research", "implement", "test"]
  args_schema Json? // JSON schema for workflow arguments
  is_template Boolean   @default(true)
  status      String    @default("active") // "active" | "archived" - User-initiated archiving
  file_exists Boolean   @default(true) // System-detected file presence on disk
  load_error  String? // Error message if workflow failed to load
  archived_at DateTime? // Timestamp when definition was archived
  created_at  DateTime  @default(now())
  updated_at  DateTime  @updatedAt

  project Project       @relation(fields: [project_id], references: [id], onDelete: Cascade)
  runs    WorkflowRun[]

  @@unique([project_id, identifier], name: "project_id_identifier")
  @@index([type])
  @@index([is_template])
  @@index([project_id])
  @@index([status])
  @@index([project_id, status])
  @@map("workflow_definitions")
}

model WorkflowRun {
  id                     String         @id @default(cuid())
  project_id             String
  user_id                String
  workflow_definition_id String
  name                   String // User-provided name for this execution
  args                   Json // Workflow arguments
  spec_file              String? // Relative path to spec file (from .agent/specs/)
  spec_content           String? // Inline spec content (alternative to spec_file)
  spec_type              String? // Spec type used (e.g., "feature", "test", "bug")
  planning_session_id    String? // Planning session to resume for spec generation
  mode                   String? // Workspace mode: "stay" | "branch" | "worktree"
  branch_name            String? // New branch name for execution
  base_branch            String? // Branch to create new branch from
  worktree_name          String? // Worktree directory name (e.g., run-abc123-feature-x)
  preserve               Boolean?  @default(false) // Keep work context for review (stay on branch / keep worktree)
  pr_url                 String? // Pull request URL (set by step.git operation: "pr")
  triggered_by           String         @default("manual") // How run was triggered: "manual" | "webhook" | "api" | "scheduled"
  webhook_event_id       String? // Link to triggering webhook event (if triggered_by="webhook")
  issue_id               String? // External issue ID (e.g., "PROJ-123", "LIN-456")
  issue_url              String? // Direct link to external issue
  issue_source           String? // External issue source: "github" | "linear" | "jira" | "generic"
  current_phase          String? // Current phase name
  current_step_index     Int            @default(0)
  status                 WorkflowStatus @default(pending)
  error_message          String?
  inngest_run_id         String? // Inngest workflow run ID for status tracking
  started_at             DateTime?
  completed_at           DateTime?
  paused_at              DateTime?
  cancelled_at           DateTime?
  created_at             DateTime       @default(now())
  updated_at             DateTime       @updatedAt

  project             Project            @relation(fields: [project_id], references: [id], onDelete: Cascade)
  user                User               @relation(fields: [user_id], references: [id], onDelete: Cascade)
  workflow_definition WorkflowDefinition @relation(fields: [workflow_definition_id], references: [id], onDelete: Cascade)
  planning_session    AgentSession?      @relation("WorkflowRunPlanningSession", fields: [planning_session_id], references: [id], onDelete: SetNull)
  webhook_event       WebhookEvent?      @relation(fields: [webhook_event_id], references: [id], onDelete: SetNull)
  steps               WorkflowRunStep[]
  events              WorkflowEvent[]
  artifacts           WorkflowArtifact[]
  container           Container?

  @@index([project_id, status])
  @@index([user_id, status])
  @@index([workflow_definition_id])
  @@index([planning_session_id])
  @@index([webhook_event_id])
  @@index([triggered_by])
  @@index([issue_source])
  @@index([status])
  @@index([inngest_run_id])
  @@map("workflow_runs")
}

model WorkflowRunStep {
  id               String     @id @default(cuid())
  workflow_run_id  String
  inngest_step_id  String // Auto-generated: "${phase}-${userStepId}" for Inngest memoization
  name             String // Display name
  step_type        StepType // Type of step for UI categorization
  phase            String // Phase this step belongs to
  status           StepStatus @default(pending)
  args             Json? // Sanitized step arguments/configuration (JSON)
  output           Json? // Sanitized execution results (success or failure)
  agent_session_id String? // Link to AgentSession (nullable - only for agent steps)
  error_message    String? // Simple error summary for UI
  started_at       DateTime?
  completed_at     DateTime?
  created_at       DateTime   @default(now())
  updated_at       DateTime   @updatedAt

  workflow_run WorkflowRun   @relation(fields: [workflow_run_id], references: [id], onDelete: Cascade)
  session      AgentSession? @relation(fields: [agent_session_id], references: [id], onDelete: Cascade)

  @@index([workflow_run_id, status])
  @@index([agent_session_id])
  @@index([status])
  @@map("workflow_run_steps")
}

model WorkflowEvent {
  id                 String            @id @default(cuid())
  workflow_run_id    String
  event_type         WorkflowEventType
  event_data         Json // Event-specific data (comment text, phase name, step info, etc.)
  phase              String? // Phase this event belongs to
  inngest_step_id    String? // Optional reference to step that triggered this event
  created_by_user_id String? // Nullable - only for user-generated events
  created_at         DateTime          @default(now())
  updated_at         DateTime          @updatedAt

  workflow_run    WorkflowRun        @relation(fields: [workflow_run_id], references: [id], onDelete: Cascade)
  created_by_user User?              @relation(fields: [created_by_user_id], references: [id], onDelete: Cascade)
  artifacts       WorkflowArtifact[]

  @@index([workflow_run_id, created_at])
  @@index([event_type])
  @@index([phase])
  @@map("workflow_events")
}

model Webhook {
  id                String        @id @default(cuid())
  project_id        String
  name              String
  description       String?
  source            WebhookSource @default(generic)
  status            WebhookStatus @default(draft)
  secret            String // HMAC secret for signature validation (32-byte hex)
  config            Json // Field mappings, conditions, source config
  error_message     String? // Error message when status is 'error'
  last_triggered_at DateTime?
  created_at        DateTime      @default(now())
  updated_at        DateTime      @updatedAt

  project Project        @relation(fields: [project_id], references: [id], onDelete: Cascade)
  events  WebhookEvent[]

  @@index([project_id])
  @@index([status])
  @@index([source])
  @@map("webhooks")
}

model WebhookEvent {
  id                 String             @id @default(cuid())
  webhook_id         String
  status             WebhookEventStatus
  payload            String // Original webhook payload
  headers            String // Request headers
  mapped_data        String? // Resolved field mappings (for debugging)
  error_message      String? // Error details if status is 'failed' or 'invalid_signature'
  processing_time_ms Int? // Time taken to process event
  created_at         DateTime           @default(now())

  webhook       Webhook       @relation(fields: [webhook_id], references: [id], onDelete: Cascade)
  workflow_runs WorkflowRun[]

  @@index([webhook_id, created_at])
  @@index([status])
  @@index([created_at])
  @@map("webhook_events")
}

model WorkflowArtifact {
  id                String   @id @default(cuid())
  workflow_run_id   String // Direct reference to run
  workflow_event_id String? // Nullable - can attach artifact to event
  name              String
  file_path         String // Relative to project root
  file_type         String // 'image', 'video', 'document', 'code', 'other'
  mime_type         String
  size_bytes        Int
  phase             String? // Phase this artifact belongs to
  inngest_step_id   String? // Optional reference to step that created this artifact
  created_at        DateTime @default(now())
  updated_at        DateTime @updatedAt

  workflow_run WorkflowRun    @relation(fields: [workflow_run_id], references: [id], onDelete: Cascade)
  event        WorkflowEvent? @relation(fields: [workflow_event_id], references: [id], onDelete: SetNull)

  @@index([workflow_run_id])
  @@index([workflow_run_id, phase])
  @@index([workflow_event_id])
  @@index([phase])
  @@map("workflow_artifacts")
}

model Project {
  id                   String               @id @default(cuid())
  name                 String
  path                 String               @unique
  is_hidden            Boolean              @default(false)
  is_starred           Boolean              @default(false)
  preview_config       Json? // Preview container configuration
  created_at           DateTime             @default(now())
  updated_at           DateTime             @updatedAt
  sessions             AgentSession[]
  workflow_definitions WorkflowDefinition[]
  workflow_runs        WorkflowRun[]
  webhooks             Webhook[]
  containers           Container[]

  @@map("projects")
}

model User {
  id              String          @id @default(uuid())
  email           String          @unique
  password_hash   String
  created_at      DateTime        @default(now())
  last_login      DateTime?
  is_active       Boolean         @default(true)
  settings        Json?
  sessions        AgentSession[]
  workflow_runs   WorkflowRun[]
  workflow_events WorkflowEvent[]

  @@map("users")
}

enum AgentType {
  claude
  codex
  cursor
  gemini
}

enum SessionType {
  chat
  workflow
  internal
}

enum SessionState {
  idle // Ready for new messages
  working // Agent actively processing
  error // Last execution failed
}

enum WorkflowStatus {
  pending
  running
  paused
  completed
  failed
  cancelled
  interrupted // Server shutdown during execution
}

enum WorkflowEventType {
  annotation_added
  workflow_created
  workflow_started
  workflow_completed
  workflow_failed
  workflow_paused
  workflow_resumed
  workflow_cancelled
  phase_started
  phase_completed
  phase_retry
  phase_failed
  step_started
  step_completed
  step_failed
  step_log
  command_executed
}

enum StepStatus {
  pending
  running
  completed
  failed
  skipped
  cancelled
}

enum StepType {
  agent
  git
  cli
  ai
  artifact
  annotation
  system
  command
  preview
}

enum WebhookSource {
  github
  linear
  jira
  generic
}

enum WebhookStatus {
  draft
  active
  paused
  error
}

enum WebhookEventStatus {
  test
  success
  filtered
  invalid_signature
  failed
  error
}

model Container {
  id              String    @id @default(cuid())
  workflow_run_id String?   @unique
  project_id      String
  status          String // pending | starting | running | stopped | failed
  ports           Json // { server: 5000, client: 5001 }
  container_ids   Json? // Array of Docker container IDs
  compose_project String? // docker compose -p {this}
  working_dir     String // Path where docker build ran
  error_message   String?
  created_at      DateTime  @default(now())
  started_at      DateTime?
  stopped_at      DateTime?

  workflow_run WorkflowRun? @relation(fields: [workflow_run_id], references: [id], onDelete: Cascade)
  project      Project      @relation(fields: [project_id], references: [id], onDelete: Cascade)

  @@index([project_id])
  @@index([status])
  @@map("containers")
}

model AgentSession {
  id                String       @id @default(uuid())
  project_id        String
  user_id           String
  name              String? // AI-generated session name (nullable for legacy sessions)
  name_generated_at DateTime? // Tracks if/when AI naming was attempted (prevents re-processing)
  agent             AgentType    @default(claude)
  type              SessionType  @default(chat)
  permission_mode   String       @default("default") // 'default' | 'plan' | 'acceptEdits' | 'bypassPermissions'
  cli_session_id    String? // Session ID from CLI tool (Claude/Codex) - needed for loading/resuming sessions
  session_path      String? // Full absolute path to session JSONL file (nullable during migration)
  metadata          Json // { totalTokens, messageCount, lastMessageAt, firstMessagePreview }
  state             SessionState @default(idle)
  error_message     String? // Error details when state is error
  is_archived       Boolean      @default(false)
  archived_at       DateTime?
  created_at        DateTime     @default(now())
  updated_at        DateTime     @updatedAt

  project              Project           @relation(fields: [project_id], references: [id], onDelete: Cascade)
  user                 User              @relation(fields: [user_id], references: [id], onDelete: Cascade)
  workflowSteps        WorkflowRunStep[]
  workflowRunsPlanning WorkflowRun[]     @relation("WorkflowRunPlanningSession")

  @@index([project_id, updated_at])
  @@index([user_id, updated_at])
  @@index([cli_session_id])
  @@index([session_path])
  @@map("agent_sessions")
}
