from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from typing import List
from sqlalchemy.orm import Session
from app.api.dependencies import ServiceContainer, get_db
from app.api import schemas
from app.db.models.agent import AgentTemplate, AgentInstance, AgentTrigger
from app.db.models import Message
from app.api.schemas import (
    AgentTemplateCreate, AgentTemplateResponse,
    AgentInstanceCreate, AgentInstanceResponse, AgentInstanceStatusUpdate
)
import uuid
import json
from app.core.orchestration.agent_loop import AgentExecutor

from sqlalchemy.orm import joinedload

def create_agents_router(services: ServiceContainer) -> APIRouter:
    router = APIRouter()

    @router.get("", response_model=List[AgentInstanceResponse])
    def get_agents(db: Session = Depends(get_db)):
        return db.query(AgentInstance).options(joinedload(AgentInstance.template)).all()
        
    @router.post("/templates", response_model=AgentTemplateResponse)
    def create_template(request: AgentTemplateCreate, db: Session = Depends(get_db)):
        template = AgentTemplate(**request.model_dump())
        db.add(template)
        db.commit()
        db.refresh(template)
        return template

    @router.post("/instances", response_model=AgentInstanceResponse)
    def create_instance(request: AgentInstanceCreate, db: Session = Depends(get_db)):
        # Verify template exists
        template = db.query(AgentTemplate).filter(AgentTemplate.id == request.template_id).first()
        if not template:
            raise HTTPException(status_code=404, detail="Template not found")
            
        instance = AgentInstance(**request.model_dump())
        db.add(instance)
        db.commit()
        db.refresh(instance)
        return instance

    @router.patch("/{id}/status", response_model=AgentInstanceResponse)
    def update_status(id: str, request: AgentInstanceStatusUpdate, db: Session = Depends(get_db)):
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
            
        instance.status = request.status
        db.commit()
        db.refresh(instance)
        return instance

    @router.patch("/{id}/config", response_model=AgentInstanceResponse)
    def update_config(id: str, request: schemas.AgentConfigUpdate, db: Session = Depends(get_db)):
        from app.db.models.session import Session as SessionModel
        
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
            
        template = db.query(AgentTemplate).filter(AgentTemplate.id == instance.template_id).first()
        
        if request.name is not None and template:
            template.name = request.name
        if request.system_prompt is not None and template:
            template.system_prompt_path = request.system_prompt
        if request.max_loop_iterations is not None and template:
            template.max_loop_iterations = request.max_loop_iterations
            
        if request.mesh_node_id is not None:
            instance.mesh_node_id = request.mesh_node_id
            
        # Update the Session overriding prompt so the running loop picks it up instantly!
        if instance.session_id:
            session = db.query(SessionModel).filter(SessionModel.id == instance.session_id).first()
            if session:
                if request.system_prompt is not None:
                    session.system_prompt_override = request.system_prompt
                if hasattr(request, 'provider_name') and request.provider_name is not None:
                    session.provider_name = request.provider_name
                if request.mesh_node_id is not None:
                    session.attached_node_ids = [request.mesh_node_id] if request.mesh_node_id else []
        
        db.commit()
        db.refresh(instance)
        return instance

    @router.post("/{id}/webhook", status_code=202)
    def webhook_receiver(id: str, payload: dict, background_tasks: BackgroundTasks, token: str = None, db: Session = Depends(get_db)):
        # Validate instance
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
            
        # Pass webhook event directly to the Agent Executor to process
        prompt = f"Webhook Event: {json.dumps(payload)}"
        background_tasks.add_task(AgentExecutor.run, instance.id, prompt, services.rag_service, services.user_service)
        return {"message": "Accepted"}

    @router.get("/{id}/triggers", response_model=List[schemas.AgentTriggerResponse])
    def get_agent_triggers(id: str, db: Session = Depends(get_db)):
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
        return db.query(AgentTrigger).filter(AgentTrigger.instance_id == id).all()

    @router.post("/{id}/triggers", response_model=schemas.AgentTriggerResponse)
    def create_agent_trigger(id: str, request: schemas.AgentTriggerCreate, db: Session = Depends(get_db)):
        trigger = AgentTrigger(**request.model_dump())
        trigger.instance_id = id # Ensure it maps safely
        
        if trigger.trigger_type == "webhook" and not trigger.webhook_secret:
            import secrets
            trigger.webhook_secret = secrets.token_hex(16)
            
        db.add(trigger)
        db.commit()
        db.refresh(trigger)
        return trigger

    @router.delete("/triggers/{trigger_id}")
    def delete_agent_trigger(trigger_id: str, db: Session = Depends(get_db)):
        trigger = db.query(AgentTrigger).filter(AgentTrigger.id == trigger_id).first()
        if not trigger:
            raise HTTPException(status_code=404, detail="Trigger not found")
        db.delete(trigger)
        db.commit()
        return {"message": "Trigger deleted successfully"}


    @router.get("/{id}/telemetry")
    def get_telemetry(id: str, db: Session = Depends(get_db)):
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
        # For MVP/Area 3, return mock telemetry data (e.g. baseline or from cgroup)
        # Real cgroup-based metrics will come in Phase 2
        return {
            "cpu_usage": 2.5,
            "memory_usage": 512,
            "network_tx": 120,
            "network_rx": 450
        }

    @router.get("/{id}/dependencies")
    def get_dependencies(id: str, db: Session = Depends(get_db)):
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Instance not found")
        return {
            "dependencies": [],
            "edges": []
        }

    @router.post("/deploy")
    def deploy_agent(
        request: schemas.DeployAgentRequest,
        background_tasks: BackgroundTasks,
        db: Session = Depends(get_db)
    ):
        """
        One-click agent deployment (Design Doc CUJ 1).
        Atomically creates: Template → Session → Instance → Locks Session → Injects initial prompt → Starts loop.
        """
        from app.db import models as db_models

        # 1. Create Template
        template = AgentTemplate(
            name=request.name,
            description=request.description,
            system_prompt_path=request.system_prompt,
            max_loop_iterations=request.max_loop_iterations
        )
        db.add(template)
        db.flush()

        # Resolve default provider mapping if user didn't select one
        resolved_provider = request.provider_name
        if not resolved_provider:
            sys_prefs = services.user_service.get_system_settings(db)
            resolved_provider = sys_prefs.get('llm', {}).get('default_provider', 'gemini')

        # 2. Create a locked Session for the agent
        new_session = db_models.Session(
            user_id="agent-system",
            provider_name=resolved_provider,
            feature_name="agent_harness",
            is_locked=True,
            system_prompt_override=request.system_prompt
        )
        db.add(new_session)
        db.flush()

        # 3. Create AgentInstance
        workspace_jail = f"/tmp/cortex/agent_{template.id[:8]}/"
        instance = AgentInstance(
            template_id=template.id,
            session_id=new_session.id,
            mesh_node_id=request.mesh_node_id,
            status="idle",
            current_workspace_jail=workspace_jail
        )
        db.add(instance)
        db.flush()

        # 4. Kick off agent loop if initial prompt was provided
        # (Message insertion is handled automatically by the RAG service execution)
        if request.initial_prompt:
            instance.status = "active"
            db.commit()
            
            async def run_wrapper():
                await AgentExecutor.run(instance.id, request.initial_prompt, services.rag_service, services.user_service)
                
            background_tasks.add_task(run_wrapper)
        else:
            db.commit()

        return {
            "template_id": template.id,
            "template_name": template.name,
            "instance_id": instance.id,
            "session_id": new_session.id,
            "status": instance.status,
            "workspace_jail": workspace_jail,
            "message": f"Agent '{request.name}' deployed successfully"
        }
    @router.delete("/{id}")
    def delete_agent(id: str, db: Session = Depends(get_db)):
        from app.db.models.agent import AgentInstance
        instance = db.query(AgentInstance).filter(AgentInstance.id == id).first()
        if not instance:
            raise HTTPException(status_code=404, detail="Agent not found")
        
        # Stop the agent loop if it was active by deleting it (the loop will hit a None instance and return)
        db.delete(instance)
        db.commit()
        return {"message": "Agent deleted successfully"}

    return router
