import { addCognitiveLog, getCognitiveLogs } from '../db.mjs';
import { askLLM, pickModel } from '../llm.mjs';
import { parseLLMJson } from '../json-utils.mjs';
import { getConfig } from '../config.mjs';

const plans = new Map();
let planCounter = 0;

export async function createPlan(objective, context = '') {
  const config = getConfig();
  if (!config.cognitive?.plannerEnabled) return null;

  const start = Date.now();
  const prompt = `Create a step-by-step execution plan for this objective.
Objective: ${objective}
${context ? `Context: ${context}` : ''}

Return JSON only:
{
  "steps": [
    { "description": "what to do", "skill": "skill-name or null", "args": {} or null, "depends_on": [] }
  ]
}
Rules: Max 8 steps. Each step should be concrete and actionable.
Available skills: build-page, write-doc, create-file, ingest, research, journal, analyze`;

  try {
    const response = await askLLM(prompt, { model: pickModel('plan') });
    const parsed = parseLLMJson(response);
    if (!parsed.ok) throw new Error('Failed to parse plan: ' + parsed.message);

    const planId = `plan-${++planCounter}-${Date.now()}`;
    const steps = (parsed.data.steps || []).map((s, i) => ({
      id: `step-${i}`,
      description: s.description || `Step ${i + 1}`,
      skill: s.skill || null,
      args: s.args || null,
      depends_on: s.depends_on || [],
      status: 'pending',
      completed_at: null,
      error: null
    }));

    const plan = { id: planId, objective, steps, created_at: new Date().toISOString() };
    plans.set(planId, plan);

    const durationMs = Date.now() - start;
    addCognitiveLog('planner', objective, `Created plan with ${steps.length} steps`, 0, durationMs);
    return plan;
  } catch (err) {
    addCognitiveLog('planner', objective, `Failed: ${err.message}`, 0, Date.now() - start);
    return null;
  }
}

export async function refinePlan(planId, feedback) {
  const plan = plans.get(planId);
  if (!plan) return null;

  const start = Date.now();
  const prompt = `Refine this plan based on feedback.
Original plan: ${JSON.stringify(plan.steps.map(s => s.description))}
Feedback: ${feedback}
Return JSON: { "steps": [{ "description": "...", "skill": "...", "args": null, "depends_on": [] }] }`;

  try {
    const response = await askLLM(prompt, { model: pickModel('plan') });
    const parsed = parseLLMJson(response);
    if (!parsed.ok) return plan;

    plan.steps = (parsed.data.steps || []).map((s, i) => ({
      id: `step-${i}`,
      description: s.description || `Step ${i + 1}`,
      skill: s.skill || null,
      args: s.args || null,
      depends_on: s.depends_on || [],
      status: 'pending',
      completed_at: null,
      error: null
    }));

    addCognitiveLog('planner', `Refine: ${feedback}`, `Refined to ${plan.steps.length} steps`, 0, Date.now() - start);
    return plan;
  } catch {
    return plan;
  }
}

export function getPlan(planId) {
  return plans.get(planId) || null;
}

export function getActivePlans() {
  return [...plans.values()].filter(p => p.steps.some(s => s.status === 'pending' || s.status === 'running'));
}

export function completeStep(planId, stepId) {
  const plan = plans.get(planId);
  if (!plan) return false;
  const step = plan.steps.find(s => s.id === stepId);
  if (!step) return false;
  step.status = 'completed';
  step.completed_at = new Date().toISOString();
  return true;
}

export function failStep(planId, stepId, error) {
  const plan = plans.get(planId);
  if (!plan) return false;
  const step = plan.steps.find(s => s.id === stepId);
  if (!step) return false;
  step.status = 'failed';
  step.error = error;
  return true;
}

export function getNextStep(planId) {
  const plan = plans.get(planId);
  if (!plan) return null;
  for (const step of plan.steps) {
    if (step.status !== 'pending') continue;
    const depsComplete = (step.depends_on || []).every(depIdx => {
      const dep = plan.steps[depIdx];
      return dep && dep.status === 'completed';
    });
    if (depsComplete) return step;
  }
  return null;
}

// For testing: clear all plans
export function _clearPlans() {
  plans.clear();
  planCounter = 0;
}

// For testing: directly insert a plan into the store
export function _addTestPlan(plan) {
  plans.set(plan.id, plan);
}
