import { generateText } from 'ai';
import { getModel } from '../agent/client.js';
import { createReadOnlyRegistry } from '../agent/tools/registry.js';
import type { Logger } from '../utils/logger.js';
import type {
  ResearchPlan,
  ResearchQuestion,
  ResearchFinding,
  ResearchReport,
  CriticFeedback,
} from './types.js';

/**
 * Base options for research agents
 */
interface AgentOptions {
  repoRoot: string;
  model: string;
  logger: Logger;
}

/**
 * Planner Agent
 *
 * Breaks down a research goal into sub-questions and creates a research plan.
 */
export async function runPlannerAgent(
  goal: string,
  options: AgentOptions
): Promise<ResearchPlan> {
  const systemPrompt = `You are a Research Planner. Your job is to break down a research goal into specific, answerable sub-questions.

For the given goal, create a research plan with:
1. A clear restatement of the goal
2. 3-7 specific sub-questions that need to be answered
3. An approach describing how to tackle the research
4. An estimated depth (shallow, medium, or deep)

Respond in JSON format:
{
  "goal": "restated goal",
  "questions": [
    {
      "id": "q1",
      "question": "specific question",
      "rationale": "why this question matters",
      "priority": "high|medium|low"
    }
  ],
  "approach": "how to approach the research",
  "estimatedDepth": "shallow|medium|deep"
}`;

  const model = getModel(options.model);

  const result = await generateText({
    model,
    system: systemPrompt,
    messages: [{ role: 'user', content: `Research goal: ${goal}` }],
  });

  try {
    const plan = JSON.parse(result.text) as Omit<ResearchPlan, 'createdAt'>;
    return {
      ...plan,
      questions: plan.questions.map((q) => ({ ...q, status: 'pending' as const })),
      createdAt: new Date().toISOString(),
    };
  } catch {
    // If JSON parsing fails, create a basic plan
    return {
      goal,
      questions: [
        {
          id: 'q1',
          question: goal,
          rationale: 'Main research question',
          priority: 'high',
          status: 'pending',
        },
      ],
      approach: 'Direct investigation of the main question',
      estimatedDepth: 'medium',
      createdAt: new Date().toISOString(),
    };
  }
}

/**
 * Researcher Agent
 *
 * Investigates a specific question and gathers evidence.
 */
export async function runResearcherAgent(
  question: ResearchQuestion,
  context: { goal: string; previousFindings: ResearchFinding[] },
  options: AgentOptions
): Promise<ResearchFinding[]> {
  const registry = createReadOnlyRegistry();
  const toolContext = {
    repoRoot: options.repoRoot,
    workingDir: options.repoRoot,
    logger: options.logger,
  };

  const previousContext =
    context.previousFindings.length > 0
      ? `\nPrevious findings:\n${context.previousFindings.map((f) => `- ${f.content}`).join('\n')}`
      : '';

  const systemPrompt = `You are a Research Investigator. Your job is to investigate a specific question and gather evidence.

Use the available tools to explore the codebase and find relevant information.

For each finding, note:
1. The content of the finding
2. The source (file path, line numbers, etc.)
3. Your confidence level (high, medium, low)
4. Supporting evidence

After investigation, respond with your findings in JSON format:
{
  "findings": [
    {
      "content": "what you found",
      "source": "where you found it",
      "confidence": "high|medium|low",
      "evidence": ["supporting evidence 1", "evidence 2"]
    }
  ]
}`;

  const model = getModel(options.model);

  const result = await generateText({
    model,
    system: systemPrompt,
    messages: [
      {
        role: 'user',
        content: `Research goal: ${context.goal}

Question to investigate: ${question.question}
Rationale: ${question.rationale}
Priority: ${question.priority}
${previousContext}

Use the tools to investigate this question thoroughly.`,
      },
    ],
    tools: registry.toAITools(toolContext),
    maxSteps: 15,
  });

  try {
    // Try to extract JSON from the response
    const jsonMatch = result.text.match(/\{[\s\S]*"findings"[\s\S]*\}/);
    if (jsonMatch) {
      const parsed = JSON.parse(jsonMatch[0]) as { findings: Omit<ResearchFinding, 'questionId' | 'timestamp'>[] };
      return parsed.findings.map((f) => ({
        ...f,
        questionId: question.id,
        timestamp: new Date().toISOString(),
      }));
    }
  } catch {
    // If parsing fails, create a finding from the response
  }

  return [
    {
      questionId: question.id,
      content: result.text,
      source: 'investigation',
      confidence: 'medium',
      evidence: [],
      timestamp: new Date().toISOString(),
    },
  ];
}

/**
 * Synthesizer Agent
 *
 * Synthesizes findings into a coherent report.
 */
export async function runSynthesizerAgent(
  plan: ResearchPlan,
  findings: ResearchFinding[],
  options: AgentOptions
): Promise<ResearchReport> {
  const findingsByQuestion = new Map<string, ResearchFinding[]>();
  for (const finding of findings) {
    const list = findingsByQuestion.get(finding.questionId) ?? [];
    list.push(finding);
    findingsByQuestion.set(finding.questionId, list);
  }

  const questionsWithFindings = plan.questions.map((q) => ({
    question: q.question,
    findings: findingsByQuestion.get(q.id) ?? [],
  }));

  const systemPrompt = `You are a Research Synthesizer. Your job is to synthesize research findings into a coherent report.

Create a report that:
1. Summarizes the key findings
2. Organizes information into logical sections
3. Draws conclusions from the evidence
4. Notes any limitations
5. Suggests follow-up research if needed

Respond in JSON format:
{
  "summary": "executive summary",
  "sections": [
    {
      "title": "section title",
      "content": "section content"
    }
  ],
  "conclusions": ["conclusion 1", "conclusion 2"],
  "limitations": ["limitation 1"],
  "suggestedFollowUp": ["follow-up 1"]
}`;

  const model = getModel(options.model);

  const result = await generateText({
    model,
    system: systemPrompt,
    messages: [
      {
        role: 'user',
        content: `Research goal: ${plan.goal}

Questions investigated:
${questionsWithFindings
  .map(
    (q) => `
## ${q.question}
Findings:
${q.findings.map((f) => `- [${f.confidence}] ${f.content} (Source: ${f.source})`).join('\n')}
`
  )
  .join('\n')}

Please synthesize these findings into a coherent report.`,
      },
    ],
  });

  try {
    const jsonMatch = result.text.match(/\{[\s\S]*"summary"[\s\S]*\}/);
    if (jsonMatch) {
      const parsed = JSON.parse(jsonMatch[0]) as Omit<ResearchReport, 'goal' | 'createdAt' | 'sections'> & {
        sections: Array<{ title: string; content: string }>;
      };

      return {
        goal: plan.goal,
        summary: parsed.summary,
        sections: parsed.sections.map((s) => ({
          ...s,
          findings: findings.filter((f) =>
            s.content.toLowerCase().includes(f.content.toLowerCase().slice(0, 50))
          ),
        })),
        conclusions: parsed.conclusions ?? [],
        limitations: parsed.limitations ?? [],
        suggestedFollowUp: parsed.suggestedFollowUp ?? [],
        createdAt: new Date().toISOString(),
      };
    }
  } catch {
    // Parsing failed
  }

  // Fallback report
  return {
    goal: plan.goal,
    summary: result.text,
    sections: [
      {
        title: 'Findings',
        content: result.text,
        findings,
      },
    ],
    conclusions: [],
    limitations: [],
    suggestedFollowUp: [],
    createdAt: new Date().toISOString(),
  };
}

/**
 * Critic Agent
 *
 * Reviews and validates research findings.
 */
export async function runCriticAgent(
  report: ResearchReport,
  findings: ResearchFinding[],
  options: AgentOptions
): Promise<CriticFeedback> {
  const systemPrompt = `You are a Research Critic. Your job is to critically evaluate research reports.

Evaluate the report on:
1. Completeness - Does it address the research goal?
2. Evidence quality - Are findings well-supported?
3. Logic - Are conclusions valid given the evidence?
4. Clarity - Is the report clear and well-organized?

Provide a score from 0-100 and detailed feedback.

Respond in JSON format:
{
  "isValid": true/false,
  "score": 0-100,
  "strengths": ["strength 1", "strength 2"],
  "weaknesses": ["weakness 1"],
  "suggestions": ["suggestion 1"],
  "requiresRevision": true/false
}`;

  const model = getModel(options.model);

  const result = await generateText({
    model,
    system: systemPrompt,
    messages: [
      {
        role: 'user',
        content: `Research goal: ${report.goal}

## Report Summary
${report.summary}

## Sections
${report.sections.map((s) => `### ${s.title}\n${s.content}`).join('\n\n')}

## Conclusions
${report.conclusions.map((c) => `- ${c}`).join('\n')}

## Limitations
${report.limitations.map((l) => `- ${l}`).join('\n')}

## Evidence Count
Total findings: ${findings.length}
High confidence: ${findings.filter((f) => f.confidence === 'high').length}
Medium confidence: ${findings.filter((f) => f.confidence === 'medium').length}
Low confidence: ${findings.filter((f) => f.confidence === 'low').length}

Please evaluate this research report.`,
      },
    ],
  });

  try {
    const jsonMatch = result.text.match(/\{[\s\S]*"isValid"[\s\S]*\}/);
    if (jsonMatch) {
      return JSON.parse(jsonMatch[0]) as CriticFeedback;
    }
  } catch {
    // Parsing failed
  }

  // Default feedback
  return {
    isValid: true,
    score: 70,
    strengths: ['Research was completed'],
    weaknesses: [],
    suggestions: [],
    requiresRevision: false,
  };
}
