"""Main Deep Research Agent implementation.

The Deep Research Agent orchestrates fact-grounded, team-values-driven research
using a multi-loop architecture with critic-gated iterations.

Key features:
- Multi-LLM loops with critic evaluation
- Evidence-first approach (V2)
- Cost-aware model escalation (V4)
- Team-aligned outputs (V6)
"""

from typing import Optional

from rich.console import Console
from rich.panel import Panel

from emdash.agent.events import AgentEventEmitter, EventType, NullEmitter
from emdash.agent.providers.factory import DEFAULT_MODEL
from emdash.agent.research.state import (
    ResearchState,
    ResearchPlan,
)
from emdash.agent.research.planner import PlannerAgent
from emdash.agent.research.researcher import ResearcherAgent
from emdash.agent.research.critic import CriticAgent
from emdash.agent.research.synthesizer import SynthesizerAgent
from emdash.agent.research.controller import ResearchController, MODEL_TIERS


class DeepResearchAgent:
    """Fact-grounded, team-values-driven research agent.
    
    Orchestrates a multi-loop research process:
    1. Planner creates research plan with questions
    2. Researcher executes tool macros, collects evidence
    3. Critic evaluates and decides: APPROVE/CONTINUE/REJECT/ESCALATE
    4. Controller manages state transitions and budgets
    5. Synthesizer produces final report
    
    Team values enforced:
    - V1: Truth over fluency - prefer "unknown" over guesses
    - V2: Evidence-first - all claims backed by tool outputs
    - V3: Reviewer-first - output includes review checklists
    - V4: Cost awareness - cheap models first, escalate when needed
    - V5: Actionable outcomes - end with concrete tasks
    - V6: Team alignment - use team vocabulary
    
    Example:
        agent = DeepResearchAgent()
        report = agent.research("How does the agent toolkit work?")
        print(report)
    """
    
    def __init__(
        self,
        planner_model: str = DEFAULT_MODEL,
        researcher_model: str = DEFAULT_MODEL,
        critic_model: str = DEFAULT_MODEL,
        synthesizer_model: str = DEFAULT_MODEL,
        max_iterations: int = 5,
        verbose: bool = True,
        emitter: Optional[AgentEventEmitter] = None,
    ):
        """Initialize the deep research agent.
        
        Args:
            planner_model: Model for planning (needs good reasoning)
            researcher_model: Model for research (fast, cost-effective)
            critic_model: Model for critique (needs good judgment)
            synthesizer_model: Model for synthesis (needs good writing)
            max_iterations: Maximum research-critique loops
            verbose: Whether to print progress
            emitter: Event emitter for unified message stream
        """
        self.emitter = emitter or NullEmitter(agent_name="DeepResearchAgent")
        
        # Pass emitter to sub-agents
        self.planner = PlannerAgent(planner_model, verbose=verbose)
        self.researcher = ResearcherAgent(researcher_model, verbose=verbose, emitter=self.emitter)
        self.critic = CriticAgent(critic_model, verbose=verbose)
        self.synthesizer = SynthesizerAgent(synthesizer_model, verbose=verbose)
        self.controller = ResearchController(verbose=verbose)
        
        self.max_iterations = max_iterations
        self.verbose = verbose
        self.console = Console()
        
        # Track current researcher model for escalation
        self._researcher_model = researcher_model
    
    def research(
        self,
        goal: str,
        context: str = "",
        budgets: Optional[dict] = None,
    ) -> str:
        """Execute deep research with critic-gated iterations.
        
        This is the main entry point. It runs the authoritative
        research loop as specified in the design:
        
        1. Plan: Create question DAG and budgets
        2. Loop:
           - Select questions (P0 first)
           - Run macros, collect evidence
           - Propose claims
           - Identify gaps
           - Critique: APPROVE/CONTINUE/REJECT/ESCALATE
           - Handle decision
        3. Synthesize: Generate final report
        
        Args:
            goal: Research goal (what you want to understand)
            context: Additional context or constraints
            budgets: Optional budget overrides {tool_calls, tokens, time_s}
            
        Returns:
            Final research report as markdown string
        """
        # Emit session start
        self.emitter.emit(EventType.SESSION_START, {
            "agent_name": "Deep Research Agent",
            "goal": goal,
            "max_iterations": self.max_iterations,
        })
        
        if self.verbose:
            self.console.print(Panel(
                f"[bold cyan]Deep Research Agent[/bold cyan]\n\n"
                f"Goal: {goal}\n"
                f"Max iterations: {self.max_iterations}",
                border_style="cyan",
            ))
        
        # 1. Create research plan
        plan = self.planner.create_plan(
            goal=goal,
            context=context,
            max_iterations=self.max_iterations,
            budgets=budgets,
        )
        
        # Initialize state
        state = ResearchState(plan=plan)
        self.controller.start_research(state)
        
        # 2. Research-Critique loop
        while True:
            # Check stopping conditions
            should_stop, stop_reason = self.controller.should_stop(state)
            if should_stop:
                if self.verbose:
                    self.console.print(f"[yellow]Stopping: {stop_reason}[/yellow]")
                break
            
            # Handle budget warnings
            self.controller.handle_budget_warning(state)
            
            if self.verbose:
                self.console.print(f"\n[bold]Iteration {state.iteration + 1}[/bold]")
            
            # Select questions to investigate
            questions = self.controller.select_questions(state, k=3)
            if not questions:
                if self.verbose:
                    self.console.print("[yellow]No more questions to investigate[/yellow]")
                break
            
            # Update researcher model if escalated
            if state.current_model_tier != "fast":
                new_model = MODEL_TIERS[state.current_model_tier]
                if new_model != self._researcher_model:
                    self._researcher_model = new_model
                    self.researcher = ResearcherAgent(new_model, verbose=self.verbose)
            
            # Run macros and collect evidence
            evidence, ctx_updates = self.researcher.run_macros(
                questions=questions,
                context=state.context,
                budget=state.remaining_budget,
            )
            
            # Update context
            state.context = self.controller.update_context(state, evidence, [])
            state.context.update(ctx_updates)
            
            # Propose claims
            prior_claims = state.get_all_claims()
            claims = self.researcher.propose_claims(
                goal=plan.goal,
                questions=questions,
                evidence=evidence,
                prior_claims=prior_claims,
            )
            
            # Update context with claims
            state.context = self.controller.update_context(state, evidence, claims)
            
            # Identify gaps
            gaps = self.researcher.identify_gaps(plan, claims, evidence)
            
            # Critique
            critique = self.critic.evaluate(
                plan=plan,
                claims=claims,
                evidence=evidence,
                gaps=gaps,
                history=state.history,
            )
            
            # Record iteration
            self.controller.record_iteration(state, evidence, claims, gaps, critique)
            
            # Handle critique decision
            if critique.decision == "APPROVE":
                if self.verbose:
                    self.console.print("[green]✓ Research approved by Critic[/green]")
                break
            
            elif critique.decision == "REJECT":
                self.controller.rollback_or_restart(state, critique)
                # Continue to next iteration
            
            elif critique.decision == "ESCALATE":
                self.controller.escalate_models_or_budget(state, critique)
                self.controller.enqueue_followups(state, critique.follow_up_questions)
            
            elif critique.decision == "CONTINUE":
                self.controller.enqueue_followups(state, critique.follow_up_questions)
            
            # Safety check
            if state.iteration >= self.max_iterations:
                if self.verbose:
                    self.console.print("[yellow]Max iterations reached[/yellow]")
                break
        
        # 3. Synthesize final report
        report = self.synthesizer.write(
            plan=state.plan,
            history=state.history,
        )
        
        if self.verbose:
            self.console.print(Panel(
                f"[green]Research complete![/green]\n\n"
                f"Iterations: {len(state.history)}\n"
                f"Evidence items: {len(state.get_all_evidence())}\n"
                f"Claims: {len(state.get_all_claims())}\n"
                f"Gaps: {len(state.get_all_gaps())}",
                border_style="green",
            ))
        
        # Emit response and session end
        self.emitter.emit_response(report)
        self.emitter.emit(EventType.SESSION_END, {"success": True})
        
        return report
    
    def get_state_summary(self, state: ResearchState) -> dict:
        """Get a summary of the research state.
        
        Args:
            state: Research state
            
        Returns:
            Summary dict
        """
        return {
            "goal": state.plan.goal,
            "iteration": state.iteration,
            "max_iterations": state.plan.max_iterations,
            "evidence_count": len(state.get_all_evidence()),
            "claims_count": len(state.get_all_claims()),
            "gaps_count": len(state.get_all_gaps()),
            "budget_used_percent": state.budget_used_percent(),
            "current_model_tier": state.current_model_tier,
            "is_approved": state.is_approved(),
            "questions_answered": len(state.answered_questions),
            "questions_total": len(state.plan.questions),
        }


def research(goal: str, **kwargs) -> str:
    """Convenience function for running deep research.
    
    Args:
        goal: Research goal
        **kwargs: Additional arguments for DeepResearchAgent
        
    Returns:
        Research report markdown
    """
    agent = DeepResearchAgent(**kwargs)
    return agent.research(goal)

