/**
 * SessionRepository - CRUD + list_active for sessions table (§3)
 *
 * Implements Repository<SessionRecord, SessionInsert, SessionUpdate>
 * per contracts §6.
 *
 * @module packages/runtime/src/storage/repositories/SessionRepository
 */

import type {
  Repository,
  TransactionHandle,
  SessionID,
  ProjectID,
  ISOTimeString,
} from '@aircoding/contracts'

import { DatabaseHandle } from '../MigrationRunner.js'

// =============================================================================
// Types - per db-schema §3
// =============================================================================

export interface SessionRecord {
  id: SessionID
  project_id: ProjectID
  project_root: string
  title?: string
  status: 'active' | 'archived' | 'deleted'
  created_at: ISOTimeString
  updated_at: ISOTimeString
  exited_at?: ISOTimeString
  model_provider_id?: string
  model_id?: string
  metadata_json?: string
}

export type SessionInsert = Omit<SessionRecord, 'id' | 'status'> & {
  id?: SessionID
}

export type SessionUpdate = Partial<Omit<SessionRecord, 'id' | 'project_id' | 'created_at' | 'status'>>

// =============================================================================
// SessionRepository
// =============================================================================

export class SessionRepository implements Repository<SessionRecord, SessionInsert, SessionUpdate> {
  private db: DatabaseHandle

  constructor(db: DatabaseHandle) {
    this.db = db
  }

  /**
   * Get a session by ID.
   */
  async get(id: SessionID, tx?: TransactionHandle): Promise<SessionRecord | undefined> {
    const stmt = (tx?.db ?? this.db).prepare('SELECT * FROM sessions WHERE id = ?')
    const row = stmt.get(id) as SessionRecord | undefined
    return row
  }

  /**
   * Insert a new session. Status is set by EventStore projection (INV-1).
   */
  async insert(record: SessionInsert, tx?: TransactionHandle): Promise<void> {
    // Get status from event-projected column, default to 'active'
    const status = 'active' // Set by EventStore.project(), not by caller

    const stmt = (tx?.db ?? this.db).prepare(`
      INSERT INTO sessions (
        id, project_id, project_root, title, status,
        created_at, updated_at, exited_at,
        model_provider_id, model_id, metadata_json
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `)

    stmt.run(
      record.id,
      record.project_id,
      record.project_root,
      record.title ?? null,
      status,
      record.created_at,
      record.updated_at,
      record.exited_at ?? null,
      record.model_provider_id ?? null,
      record.model_id ?? null,
      record.metadata_json ?? null,
    )
  }

  /**
   * Update an existing session. Status changes only via EventStore projection (INV-1).
   */
  async update(id: SessionID, patch: SessionUpdate, tx?: TransactionHandle): Promise<void> {
    const fields: string[] = []
    const values: unknown[] = []

    if (patch.title !== undefined) {
      fields.push('title = ?')
      values.push(patch.title)
    }
    // NOTE: status is NOT updatable here - only EventStore.project() writes status columns
    if (patch.updated_at !== undefined) {
      fields.push('updated_at = ?')
      values.push(patch.updated_at)
    }
    if (patch.exited_at !== undefined) {
      fields.push('exited_at = ?')
      values.push(patch.exited_at)
    }
    if (patch.model_provider_id !== undefined) {
      fields.push('model_provider_id = ?')
      values.push(patch.model_provider_id)
    }
    if (patch.model_id !== undefined) {
      fields.push('model_id = ?')
      values.push(patch.model_id)
    }
    if (patch.metadata_json !== undefined) {
      fields.push('metadata_json = ?')
      values.push(patch.metadata_json)
    }

    if (fields.length === 0) {
      return // Nothing to update
    }

    values.push(id)
    const stmt = (tx?.db ?? this.db).prepare(`UPDATE sessions SET ${fields.join(', ')} WHERE id = ?`)
    stmt.run(...values)
  }

  // =============================================================================
  // Extra methods
  // =============================================================================

  /**
   * List active sessions for a project.
   */
  async list_active(project_id: ProjectID): Promise<SessionRecord[]> {
    const stmt = this.db.prepare(
      'SELECT * FROM sessions WHERE project_id = ? AND status = ? ORDER BY created_at DESC',
    )
    return stmt.all(project_id, 'active') as SessionRecord[]
  }
}