from __future__ import annotations

from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel, Field

from backend.oracle.action_service import oracle_action_service
from backend.oracle.natural_db_agent import natural_db_agent
from backend.oracle.persona_service import persona_service
from backend.services.mcp_registry import mcp_registry
from backend.services.nemoclaw_runtime import nemoclaw_runtime
from backend.services.runtime_llm_service import runtime_llm_service

router = APIRouter()


class WorkflowPreviewRequest(BaseModel):
    prompt: str = Field(..., min_length=1, max_length=4096)
    tenant_id: str = "tenant_velocity"
    actor_role: str = "sales_director"


class MCPExecuteRequest(BaseModel):
    tool_name: str = Field(..., min_length=1, max_length=128)
    query: str = Field(..., min_length=1, max_length=1024)


class OracleWritebackRequest(BaseModel):
    action_id: str
    tenant_id: str = "tenant_velocity"
    actor_id: str = "oracle_operator"
    target_entity_type: str = Field(..., min_length=1, max_length=64)
    target_entity_id: str = Field(..., min_length=1, max_length=128)
    action_type: str = Field(default="lead_writeback", min_length=1, max_length=128)
    writeback_payload: dict = Field(default_factory=dict)


class OracleQueryRequest(BaseModel):
    prompt: str = Field(..., min_length=1, max_length=4096)
    row_limit: int = Field(default=100, ge=1, le=500)
    context: dict = Field(default_factory=dict)


@router.get("/health")
async def oracle_health() -> dict:
    return {
        "status": "ok",
        "persona": await persona_service.health(),
        "mcp_tools": mcp_registry.list_tools(),
        "runtime_llm": await runtime_llm_service.list_providers(),
    }


@router.get("/data-health")
async def oracle_data_health(request: Request) -> dict:
    pool = getattr(request.app.state, "db_pool", None)
    if pool is None:
        raise HTTPException(status_code=503, detail="Database unavailable.")
    async with pool.acquire() as conn:
        data = await natural_db_agent.data_health(conn)
    return {
        "status": "ok",
        "data": data,
    }


@router.get("/schema-catalog")
async def oracle_schema_catalog(request: Request) -> dict:
    pool = getattr(request.app.state, "db_pool", None)
    if pool is None:
        raise HTTPException(status_code=503, detail="Database unavailable.")
    async with pool.acquire() as conn:
        catalog = await natural_db_agent.schema_catalog(conn)
    return {"status": "ok", "data": catalog}


@router.post("/query")
async def oracle_query(request: Request, payload: OracleQueryRequest) -> dict:
    pool = getattr(request.app.state, "db_pool", None)
    if pool is None:
        raise HTTPException(status_code=503, detail="Database unavailable.")
    async with pool.acquire() as conn:
        result = await natural_db_agent.execute_prompt(payload.prompt, row_limit=payload.row_limit, conn=conn)
    return {"status": "ok", "data": result.as_dict()}


@router.get("/mcp/tools")
async def oracle_mcp_tools() -> dict:
    return {"status": "ok", "data": mcp_registry.list_tools()}


@router.post("/mcp/execute")
async def oracle_mcp_execute(request: Request, payload: MCPExecuteRequest) -> dict:
    pool = getattr(request.app.state, "db_pool", None)
    result = await mcp_registry.execute(payload.tool_name, payload.query, crm_pool=pool)
    return {"status": "ok", "data": result}


@router.post("/workflow/preview")
async def workflow_preview(payload: WorkflowPreviewRequest) -> dict:
    persona_plan = await persona_service.plan_for_prompt(
        prompt=payload.prompt,
        tenant_id=payload.tenant_id,
        actor_role=payload.actor_role,
    )
    return {
        "status": "ok",
        "data": {
            "persona_plan": persona_plan,
            "workflow": nemoclaw_runtime.build_workflow_dispatch(
                prompt=payload.prompt,
                tenant_id=payload.tenant_id,
                actor_role=payload.actor_role,
                component_templates=persona_plan["recommendedTemplates"],
            ),
        },
    }


@router.get("/actions")
async def list_oracle_actions(status: str | None = None, limit: int = 50) -> dict:
    actions = await oracle_action_service.list_actions(status=status, limit=limit)
    return {"status": "ok", "data": actions, "meta": {"count": len(actions)}}


@router.get("/actions/{action_id}")
async def get_oracle_action(action_id: str) -> dict:
    action = await oracle_action_service.get_action(action_id)
    if not action:
        raise HTTPException(status_code=404, detail=f"Oracle action '{action_id}' not found.")
    return {"status": "ok", "data": action}


@router.post("/actions/writeback")
async def apply_oracle_writeback(request: Request, payload: OracleWritebackRequest) -> dict:
    result = await oracle_action_service.apply_writeback(payload.model_dump())
    if hasattr(request.app.state, "broadcast_crm_event"):
        await request.app.state.broadcast_crm_event(
            {
                "type": "oracle_writeback",
                "entity": payload.target_entity_type,
                "entity_id": payload.target_entity_id,
                "action_id": payload.action_id,
                "payload": result["resultPayload"],
            }
        )
    return {"status": "ok", "data": result}
