import { logger } from "../../core/monitoring/logger.js";
class TaskAwareContextManager {
  db;
  frameManager;
  projectId;
  constructor(db, frameManager, projectId) {
    this.db = db;
    this.frameManager = frameManager;
    this.projectId = projectId;
    this.initializeTaskSchema();
  }
  initializeTaskSchema() {
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS tasks (
        task_id TEXT PRIMARY KEY,
        frame_id TEXT NOT NULL,
        anchor_id TEXT,
        name TEXT NOT NULL,
        description TEXT,
        status TEXT DEFAULT 'pending',
        priority TEXT DEFAULT 'medium',
        parent_task_id TEXT,
        depends_on TEXT DEFAULT '[]',
        assigned_to TEXT,
        estimated_effort INTEGER,
        actual_effort INTEGER,
        created_at INTEGER DEFAULT (unixepoch()),
        started_at INTEGER,
        completed_at INTEGER,
        blocked_reason TEXT,
        context_tags TEXT DEFAULT '[]',
        metadata TEXT DEFAULT '{}',
        FOREIGN KEY(frame_id) REFERENCES frames(frame_id),
        FOREIGN KEY(anchor_id) REFERENCES anchors(anchor_id),
        FOREIGN KEY(parent_task_id) REFERENCES tasks(task_id)
      );

      CREATE TABLE IF NOT EXISTS task_dependencies (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        task_id TEXT NOT NULL,
        depends_on_task_id TEXT NOT NULL,
        dependency_type TEXT DEFAULT 'blocks',
        created_at INTEGER DEFAULT (unixepoch()),
        FOREIGN KEY(task_id) REFERENCES tasks(task_id),
        FOREIGN KEY(depends_on_task_id) REFERENCES tasks(task_id)
      );

      CREATE TABLE IF NOT EXISTS context_access_log (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        request_id TEXT NOT NULL,
        task_ids TEXT, -- JSON array of relevant task IDs
        context_items TEXT, -- JSON array of included context items
        relevance_scores TEXT, -- JSON object of item -> score mappings
        total_tokens INTEGER,
        query_hash TEXT,
        timestamp INTEGER DEFAULT (unixepoch())
      );

      CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
      CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
      CREATE INDEX IF NOT EXISTS idx_tasks_frame ON tasks(frame_id);
      CREATE INDEX IF NOT EXISTS idx_task_deps ON task_dependencies(task_id);
    `);
  }
  /**
   * Create task from TODO anchor or standalone
   */
  createTask(options) {
    const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const frameId = options.frameId || this.frameManager.getCurrentFrameId();
    if (!frameId) {
      throw new Error("No active frame for task creation");
    }
    const task = {
      task_id: taskId,
      frame_id: frameId,
      anchor_id: options.anchorId,
      name: options.name,
      description: options.description,
      status: "pending",
      priority: options.priority || "medium",
      parent_task_id: options.parentTaskId,
      depends_on: options.dependsOn || [],
      estimated_effort: options.estimatedEffort,
      created_at: Math.floor(Date.now() / 1e3),
      context_tags: options.contextTags || [],
      metadata: options.metadata || {}
    };
    this.db.prepare(
      `
      INSERT INTO tasks (
        task_id, frame_id, anchor_id, name, description, status, priority,
        parent_task_id, depends_on, estimated_effort, created_at, context_tags, metadata
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `
    ).run(
      task.task_id,
      task.frame_id,
      task.anchor_id,
      task.name,
      task.description,
      task.status,
      task.priority,
      task.parent_task_id,
      JSON.stringify(task.depends_on),
      task.estimated_effort,
      task.created_at,
      JSON.stringify(task.context_tags),
      JSON.stringify(task.metadata)
    );
    if (task.depends_on.length > 0) {
      const dependencyStmt = this.db.prepare(`
        INSERT INTO task_dependencies (task_id, depends_on_task_id) VALUES (?, ?)
      `);
      task.depends_on.forEach((depTaskId) => {
        dependencyStmt.run(taskId, depTaskId);
      });
    }
    this.frameManager.addEvent("decision", {
      action: "create_task",
      task_id: taskId,
      name: task.name,
      priority: task.priority
    });
    logger.info("Created task", { taskId, name: task.name, frameId });
    return taskId;
  }
  /**
   * Update task status with automatic time tracking
   */
  updateTaskStatus(taskId, newStatus, reason) {
    const task = this.getTask(taskId);
    if (!task) throw new Error(`Task not found: ${taskId}`);
    const now = Math.floor(Date.now() / 1e3);
    const updates = { status: newStatus };
    if (newStatus === "in_progress" && task.status === "pending") {
      updates.started_at = now;
    } else if (newStatus === "completed" && task.status === "in_progress") {
      updates.completed_at = now;
      if (task.started_at) {
        updates.actual_effort = now - task.started_at;
      }
    } else if (newStatus === "blocked") {
      updates.blocked_reason = reason || "No reason provided";
    }
    const setClause = Object.keys(updates).map((key) => `${key} = ?`).join(", ");
    const values = Object.values(updates);
    this.db.prepare(`UPDATE tasks SET ${setClause} WHERE task_id = ?`).run(...values, taskId);
    this.frameManager.addEvent("observation", {
      action: "task_status_change",
      task_id: taskId,
      old_status: task.status,
      new_status: newStatus,
      reason
    });
    logger.info("Updated task status", {
      taskId,
      oldStatus: task.status,
      newStatus
    });
  }
  /**
   * Assemble context optimized for active tasks and query
   */
  assembleTaskAwareContext(request) {
    const startTime = Date.now();
    const activeTasks = this.getActiveTasks(request.taskFocus);
    const blockedTasks = this.getBlockedTasks();
    const contextItems = this.selectRelevantContext(activeTasks, request);
    const { context, totalTokens, relevanceScores } = this.buildContextString(
      contextItems,
      activeTasks,
      request.maxTokens || 4e3
    );
    this.logContextAccess({
      taskIds: activeTasks.map((t) => t.task_id),
      contextItems: contextItems.map((item) => item.id),
      relevanceScores,
      totalTokens,
      query: request.query || ""
    });
    const metadata = {
      includedTasks: activeTasks,
      contextSources: contextItems.map((item) => `${item.type}:${item.id}`),
      totalTokens,
      relevanceScores
    };
    logger.info("Assembled task-aware context", {
      activeTasks: activeTasks.length,
      blockedTasks: blockedTasks.length,
      contextItems: contextItems.length,
      totalTokens,
      assemblyTimeMs: Date.now() - startTime
    });
    return { context, metadata };
  }
  /**
   * Get tasks that are currently active or should be in context
   */
  getActiveTasks(taskFocus) {
    let query = `
      SELECT * FROM tasks 
      WHERE status IN ('in_progress', 'pending') 
    `;
    let params = [];
    if (taskFocus && taskFocus.length > 0) {
      query += ` AND task_id IN (${taskFocus.map(() => "?").join(",")})`;
      params = taskFocus;
    }
    query += ` ORDER BY priority DESC, created_at ASC`;
    const rows = this.db.prepare(query).all(...params);
    return this.hydrateTasks(rows);
  }
  getBlockedTasks() {
    const rows = this.db.prepare(
      `
      SELECT * FROM tasks WHERE status = 'blocked' ORDER BY priority DESC
    `
    ).all();
    return this.hydrateTasks(rows);
  }
  /**
   * Select context items relevant to active tasks
   */
  selectRelevantContext(activeTasks, request) {
    const contextItems = [];
    const frameIds = [...new Set(activeTasks.map((t) => t.frame_id))];
    frameIds.forEach((frameId) => {
      const frame = this.frameManager.getFrame(frameId);
      if (frame) {
        const score = this.calculateFrameRelevance(
          frame,
          activeTasks,
          request.query
        );
        contextItems.push({
          id: frameId,
          type: "frame",
          content: `Frame: ${frame.name} (${frame.type})`,
          relevanceScore: score,
          tokenEstimate: frame.name.length + 20
        });
      }
    });
    const anchors = this.getRelevantAnchors(frameIds, request);
    anchors.forEach((anchor) => {
      const score = this.calculateAnchorRelevance(
        anchor,
        activeTasks,
        request.query
      );
      contextItems.push({
        id: anchor.anchor_id,
        type: "anchor",
        content: `${anchor.type}: ${anchor.text}`,
        relevanceScore: score,
        tokenEstimate: anchor.text.length + 10
      });
    });
    if (request.includeHistory) {
      frameIds.forEach((frameId) => {
        const events = this.frameManager.getFrameEvents(frameId, 5);
        events.forEach((event) => {
          const score = this.calculateEventRelevance(
            event,
            activeTasks,
            request.query
          );
          if (score > 0.3) {
            contextItems.push({
              id: event.event_id,
              type: "event",
              content: `Event: ${event.event_type}`,
              relevanceScore: score,
              tokenEstimate: 30
            });
          }
        });
      });
    }
    return contextItems.sort((a, b) => b.relevanceScore - a.relevanceScore);
  }
  buildContextString(contextItems, activeTasks, maxTokens) {
    let context = "# Active Task Context\n\n";
    let totalTokens = 20;
    const relevanceScores = {};
    context += "## Current Tasks\n";
    activeTasks.forEach((task) => {
      const line = `- [${task.status.toUpperCase()}] ${task.name} (${task.priority})
`;
      context += line;
      totalTokens += line.length / 4;
      relevanceScores[task.task_id] = 1;
    });
    context += "\n";
    context += "## Relevant Context\n";
    for (const item of contextItems) {
      if (totalTokens + item.tokenEstimate > maxTokens) break;
      context += `${item.content}
`;
      totalTokens += item.tokenEstimate;
      relevanceScores[item.id] = item.relevanceScore;
    }
    return { context, totalTokens, relevanceScores };
  }
  // Relevance scoring methods
  calculateFrameRelevance(frame, activeTasks, query) {
    let score = 0.5;
    if (activeTasks.some((t) => t.frame_id === frame.frame_id)) {
      score += 0.4;
    }
    if (query) {
      const queryLower = query.toLowerCase();
      if (frame.name.toLowerCase().includes(queryLower)) {
        score += 0.3;
      }
    }
    const ageHours = (Date.now() / 1e3 - frame.created_at) / 3600;
    if (ageHours < 24) score += 0.2;
    return Math.min(score, 1);
  }
  calculateAnchorRelevance(anchor, activeTasks, query) {
    let score = 0.3;
    if (anchor.type === "TODO") score += 0.4;
    if (anchor.type === "DECISION") score += 0.3;
    if (anchor.type === "CONSTRAINT") score += 0.2;
    score += anchor.priority / 10 * 0.2;
    if (query) {
      const queryLower = query.toLowerCase();
      if (anchor.text.toLowerCase().includes(queryLower)) {
        score += 0.3;
      }
    }
    return Math.min(score, 1);
  }
  calculateEventRelevance(event, _activeTasks, _query) {
    let score = 0.1;
    if (event.event_type === "decision") score += 0.4;
    if (event.event_type === "tool_call") score += 0.3;
    if (event.event_type === "observation") score += 0.2;
    const ageHours = (Date.now() / 1e3 - event.ts) / 3600;
    if (ageHours < 1) score += 0.3;
    else if (ageHours < 6) score += 0.2;
    return Math.min(score, 1);
  }
  // Helper methods
  getTask(taskId) {
    const row = this.db.prepare(`SELECT * FROM tasks WHERE task_id = ?`).get(taskId);
    return row ? this.hydrateTask(row) : void 0;
  }
  getRelevantAnchors(frameIds, _request) {
    if (frameIds.length === 0) return [];
    const placeholders = frameIds.map(() => "?").join(",");
    const rows = this.db.prepare(
      `
      SELECT * FROM anchors 
      WHERE frame_id IN (${placeholders})
      ORDER BY priority DESC, created_at DESC
      LIMIT 20
    `
    ).all(...frameIds);
    return rows.map((row) => ({
      ...row,
      metadata: JSON.parse(row.metadata || "{}")
    }));
  }
  hydrateTasks(rows) {
    return rows.map(this.hydrateTask);
  }
  hydrateTask = (row) => ({
    ...row,
    depends_on: JSON.parse(row.depends_on || "[]"),
    context_tags: JSON.parse(row.context_tags || "[]"),
    metadata: JSON.parse(row.metadata || "{}")
  });
  logContextAccess(data) {
    const requestId = `ctx_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
    this.db.prepare(
      `
      INSERT INTO context_access_log (
        request_id, task_ids, context_items, relevance_scores, total_tokens, query_hash
      ) VALUES (?, ?, ?, ?, ?, ?)
    `
    ).run(
      requestId,
      JSON.stringify(data.taskIds),
      JSON.stringify(data.contextItems),
      JSON.stringify(data.relevanceScores),
      data.totalTokens,
      this.hashString(data.query)
    );
  }
  hashString(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash = hash & hash;
    }
    return hash.toString(16);
  }
}
export {
  TaskAwareContextManager
};
//# sourceMappingURL=task-aware-context.js.map
