from fastapi import APIRouter, HTTPException, BackgroundTasks, Depends
from typing import List
import uuid
from datetime import datetime
import structlog

from .schemas import (
    TaskCreate, TaskResponse, TaskStatus, ReportResponse,
    ProjectCreate, ProjectResponse, ExecutorHealth,
)
from app.state import create_initial_state
from app.executors import EXECUTOR_REGISTRY, get_executor
from app.memory import ProjectMemory

logger = structlog.get_logger()

# In-memory task store (replace with DB in production)
_task_store: dict = {}
_project_store: dict = {}

router = APIRouter()
memory = ProjectMemory()


# ─── Tasks ────────────────────────────────────────────────────────────────────

@router.post("/tasks", response_model=TaskResponse, tags=["Tasks"])
async def create_task(payload: TaskCreate, background_tasks: BackgroundTasks):
    """提交一个新的工程任务"""
    state = create_initial_state(
        user_request=payload.user_request,
        repo_path=payload.repo_path,
        executor=payload.executor,
        project_id=payload.project_id,
    )
    state["max_attempts"] = payload.max_attempts

    task_id = state["task_id"]
    _task_store[task_id] = {
        "state": state,
        "graph_type": payload.graph_type,
        "status": "queued",
    }

    background_tasks.add_task(_run_task, task_id, payload.graph_type)

    return TaskResponse(
        task_id=task_id,
        status="queued",
        user_request=payload.user_request,
        repo_path=payload.repo_path,
        executor=payload.executor,
        graph_type=payload.graph_type,
        created_at=state["created_at"],
        message=f"Task {task_id} queued for {payload.graph_type} workflow",
    )


@router.get("/tasks", response_model=List[TaskStatus], tags=["Tasks"])
async def list_tasks():
    """列出所有任务"""
    return [
        TaskStatus(
            task_id=tid,
            status=t["state"].get("status", "unknown"),
            attempts=t["state"].get("attempts", 0),
            error=t["state"].get("error"),
        )
        for tid, t in _task_store.items()
    ]


@router.get("/tasks/{task_id}", response_model=TaskStatus, tags=["Tasks"])
async def get_task(task_id: str):
    """获取任务状态"""
    entry = _task_store.get(task_id)
    if not entry:
        raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
    state = entry["state"]
    return TaskStatus(
        task_id=task_id,
        status=state.get("status", "unknown"),
        attempts=state.get("attempts", 0),
        code_result=state.get("code_result"),
        test_result=state.get("test_result"),
        review_result=state.get("review_result"),
        diff_result=state.get("diff_result"),
        error=state.get("error"),
    )


# ─── Reports ──────────────────────────────────────────────────────────────────

@router.get("/reports/{task_id}", response_model=ReportResponse, tags=["Reports"])
async def get_report(task_id: str):
    """获取任务报告"""
    entry = _task_store.get(task_id)
    if not entry:
        raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
    state = entry["state"]
    if not state.get("report"):
        raise HTTPException(status_code=404, detail="Report not generated yet")
    return ReportResponse(
        task_id=task_id,
        report=state.get("report", ""),
        pr_description=state.get("pr_description", ""),
        test_summary=state.get("test_result"),
        review_summary=state.get("review_result"),
        diff_summary=state.get("diff_result"),
    )


# ─── Projects ─────────────────────────────────────────────────────────────────

@router.post("/projects", response_model=ProjectResponse, tags=["Projects"])
async def create_project(payload: ProjectCreate):
    """创建项目"""
    project_id = str(uuid.uuid4())
    _project_store[project_id] = {
        "id": project_id,
        "name": payload.name,
        "repo_path": payload.repo_path,
        "description": payload.description,
        "created_at": datetime.utcnow().isoformat(),
        "tasks": [],
    }
    return ProjectResponse(
        project_id=project_id,
        name=payload.name,
        repo_path=payload.repo_path,
        description=payload.description,
        created_at=_project_store[project_id]["created_at"],
    )


@router.get("/projects", response_model=List[ProjectResponse], tags=["Projects"])
async def list_projects():
    """列出所有项目"""
    return [
        ProjectResponse(
            project_id=p["id"],
            name=p["name"],
            repo_path=p["repo_path"],
            description=p["description"],
            created_at=p["created_at"],
            task_count=len(p["tasks"]),
        )
        for p in _project_store.values()
    ]


# ─── Health & Executors ───────────────────────────────────────────────────────

@router.get("/health", tags=["System"])
async def health():
    return {"status": "ok", "version": "2.0.0"}


@router.get("/executors", response_model=List[ExecutorHealth], tags=["System"])
async def list_executors():
    """列出所有执行器及其可用状态"""
    results = []
    for name, cls in EXECUTOR_REGISTRY.items():
        try:
            executor = cls(repo_path=".")
            available = executor.health_check()
            results.append(ExecutorHealth(name=name, available=available))
        except Exception as e:
            results.append(ExecutorHealth(name=name, available=False, details=str(e)))
    return results


# ─── Background task runner ───────────────────────────────────────────────────

async def _run_task(task_id: str, graph_type: str):
    from app.graphs import GRAPH_REGISTRY
    entry = _task_store.get(task_id)
    if not entry:
        return

    graph = GRAPH_REGISTRY.get(graph_type)
    if not graph:
        _task_store[task_id]["state"]["error"] = f"Unknown graph type: {graph_type}"
        _task_store[task_id]["state"]["status"] = "failed"
        return

    _task_store[task_id]["state"]["status"] = "running"
    try:
        final_state = graph.invoke(entry["state"])
        _task_store[task_id]["state"] = final_state
        # Save to memory
        memory.save_task(task_id, dict(final_state))
    except Exception as e:
        logger.error("Task execution failed", task_id=task_id, error=str(e))
        _task_store[task_id]["state"]["status"] = "failed"
        _task_store[task_id]["state"]["error"] = str(e)
