"""
Bugfix Graph
analyze_bug → fix_bug → run_tests → review_fix → report
"""
from typing import Literal
import structlog
from langgraph.graph import StateGraph, END

from app.state import EngineeringState
from app.agents import DeveloperAgent, TesterAgent, ReviewerAgent, ReporterAgent
from app.tools.sandbox import SandboxManager

logger = structlog.get_logger()


def node_analyze_bug(state: EngineeringState) -> EngineeringState:
    logger.info("Bugfix: analyze_bug")
    # Sandbox for safe editing
    manager = SandboxManager()
    sandbox_path = manager.create_sandbox(state["task_id"], state["repo_path"])
    return {
        **state,
        "sandbox_path": sandbox_path,
        "status": "bug_analyzed",
        "current_task": f"Fix bug: {state['user_request']}",
    }


def node_fix_bug(state: EngineeringState) -> EngineeringState:
    logger.info("Bugfix: fix_bug", attempts=state.get("attempts", 0))
    developer = DeveloperAgent()
    result = developer.fix_bug(state, state.get("user_request", ""))

    diff_result = {}
    if state.get("sandbox_path") and state.get("repo_path"):
        try:
            manager = SandboxManager()
            diff_result = manager.get_diff(state["sandbox_path"], state["repo_path"])
        except Exception:
            pass

    return {
        **state,
        "code_result": {"output": result.output, "error": result.error, "success": result.success},
        "diff_result": diff_result,
        "status": "fixed" if result.success else "fix_failed",
        "attempts": state.get("attempts", 0) + 1,
    }


def node_run_tests(state: EngineeringState) -> EngineeringState:
    logger.info("Bugfix: run_tests")
    tester = TesterAgent()
    test_result = tester.run_tests(state)
    return {**state, "test_result": test_result, "status": "tested" if test_result.get("success") else "test_failed"}


def node_review_fix(state: EngineeringState) -> EngineeringState:
    logger.info("Bugfix: review_fix")
    reviewer = ReviewerAgent()
    review_result = reviewer.review(state)
    return {**state, "review_result": review_result, "status": "reviewed"}


def node_report(state: EngineeringState) -> EngineeringState:
    logger.info("Bugfix: report")
    reporter = ReporterAgent(reports_dir="./reports")
    output = reporter.generate_report(state)
    return {**state, "report": output["report"], "pr_description": output["pr_description"], "status": "completed"}


def route_after_fix(state: EngineeringState) -> Literal["run_tests", "fix_bug", "report"]:
    if state["status"] == "fixed":
        return "run_tests"
    if state.get("attempts", 0) < state.get("max_attempts", 3):
        return "fix_bug"
    return "report"


def route_after_tests(state: EngineeringState) -> Literal["review_fix", "fix_bug"]:
    if state["status"] == "tested":
        return "review_fix"
    if state.get("attempts", 0) < state.get("max_attempts", 3):
        return "fix_bug"
    return "review_fix"


def build_bugfix_graph() -> StateGraph:
    graph = StateGraph(EngineeringState)
    graph.add_node("analyze_bug", node_analyze_bug)
    graph.add_node("fix_bug", node_fix_bug)
    graph.add_node("run_tests", node_run_tests)
    graph.add_node("review_fix", node_review_fix)
    graph.add_node("report", node_report)

    graph.set_entry_point("analyze_bug")
    graph.add_edge("analyze_bug", "fix_bug")
    graph.add_conditional_edges("fix_bug", route_after_fix, {
        "run_tests": "run_tests", "fix_bug": "fix_bug", "report": "report"
    })
    graph.add_conditional_edges("run_tests", route_after_tests, {
        "review_fix": "review_fix", "fix_bug": "fix_bug"
    })
    graph.add_edge("review_fix", "report")
    graph.add_edge("report", END)
    return graph.compile()


bugfix_graph = build_bugfix_graph()
