#!/usr/bin/env python3
"""
{{ project_name }} - Main Application
{{ description }}

Domain: {{ domain }}
Generated by ABI-Core CLI
"""

import os
import json
import logging
import asyncio
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, List, Optional

import uvicorn
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

from config.config import config
from abi_core.common.utils import abi_logging

# Configure logging
logging.basicConfig(
    level=getattr(logging, config.log_level),
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Lifespan context manager (replaces deprecated on_event)
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan - startup and shutdown"""
    
    # Startup
    logger.info(f"🚀 Starting {{ project_name }}")
    logger.info(f"📋 Description: {{ description }}")
    logger.info(f"🏷️ Domain: {{ domain }}")
    logger.info(f"⚙️ Configuration: {config.to_dict()}")
    
    {% if with_semantic_layer %}
    # Test semantic layer connection
    try:
        agents = await semantic_client.list_agents()
        logger.info(f"✅ Semantic layer connected - {len(agents)} agents registered")
    except Exception as e:
        logger.warning(f"⚠️ Semantic layer connection failed: {e}")
    {% endif %}
    
    {% if with_guardian %}
    # Test guardian connection
    try:
        import httpx
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"http://{config.guardian_host}:{config.guardian_port}/health",
                timeout=5.0
            )
            if response.status_code == 200:
                logger.info("✅ Guardian security service connected")
            else:
                logger.warning(f"⚠️ Guardian service returned {response.status_code}")
    except Exception as e:
        logger.warning(f"⚠️ Guardian connection failed: {e}")
    {% endif %}
    
    yield  # Application runs here
    
    # Shutdown
    logger.info("🛑 Shutting down {{ project_name }}")

# FastAPI app with lifespan
app = FastAPI(
    title="{{ project_name }}",
    description="{{ description }}",
    version="{{ version | default('0.1.0') }}",
    docs_url="/docs",
    redoc_url="/redoc",
    lifespan=lifespan
)

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Pydantic models
class AgentRequest(BaseModel):
    query: str
    context: Optional[Dict[str, Any]] = None

class AgentResponse(BaseModel):
    agent_id: Optional[str]
    agent_name: Optional[str]
    response: str
    metadata: Dict[str, Any]

{% if with_semantic_layer %}
class SemanticLayerClient:
    """Client for semantic layer service using MCP protocol"""
    
    def __init__(self):
        # Extract hostname from URL if it contains protocol
        if config.semantic_layer_host.startswith('http://') or config.semantic_layer_host.startswith('https://'):
            from urllib.parse import urlparse
            parsed = urlparse(config.semantic_layer_host)
            self.host = parsed.hostname
            self.port = parsed.port or config.semantic_layer_port
        else:
            self.host = config.semantic_layer_host
            self.port = config.semantic_layer_port
        self.transport = 'streamable-http'
        
    async def find_agent(self, query: str) -> Optional[Dict[str, Any]]:
        """Find best agent for query using MCP client"""
        from abi_core.abi_mcp import client
        from abi_core.security.agent_auth import with_agent_context
        
        try:
            # Build context for system authentication (no agent card needed)
            ctx = with_agent_context(
                agent_id="system-web-api",
                tool_name="find_agent",
                mcp_method="callTool",
                user_email="system@{{ project_name }}",
                query=query
            )
            
            async with client.init_session(self.host, self.port, self.transport) as session:
                result = await client.find_agent(session, query, ctx)
                
                if result.isError:
                    logger.error(f"MCP error: {result.content}")
                    return None
                
                # Parse the result content
                if hasattr(result.content, 'text'):
                    import json
                    agent_data = json.loads(result.content.text)
                    return agent_data
                elif isinstance(result.content, list) and len(result.content) > 0:
                    # Handle list response
                    content_item = result.content[0]
                    if hasattr(content_item, 'text'):
                        import json
                        agent_data = json.loads(content_item.text)
                        return agent_data
                
                return None
                    
        except Exception as e:
            logger.error(f"Error contacting semantic layer via MCP: {e}")
            return None
    
    async def list_agents(self) -> List[Dict[str, Any]]:
        """List all registered agents using MCP resource"""
        from abi_core.abi_mcp import client
        from abi_core.security.agent_auth import with_agent_context
        
        try:
            # Build context for system authentication (no agent card needed)
            ctx = with_agent_context(
                agent_id="system-web-api",
                tool_name="list_agents",
                mcp_method="readResource",
                user_email="system@{{ project_name }}",
                query="list all agents"
            )
            
            async with client.init_session(self.host, self.port, self.transport) as session:
                # Use the resource endpoint to list all agents
                resource_uri = "resource://agent_cards/list/all"
                result = await client.find_resource(session, resource_uri)
                
                if hasattr(result, 'contents') and result.contents:
                    # Parse the resource content
                    content = result.contents[0]
                    if hasattr(content, 'text'):
                        import json
                        data = json.loads(content.text)
                        if data:
                            return data.get("agent_cards", [])
                
                return []
                    
        except Exception as e:
            logger.error(f"Error listing agents via MCP: {e}")
            return []

# Initialize semantic layer client
semantic_client = SemanticLayerClient()
{% endif %}

{% if with_guardian %}
class GuardianClient:
    """Client for guardian security service"""
    
    def __init__(self):
        # guardian_host puede incluir http://, verificar para no duplicar
        if hasattr(config, 'guardian_url') and config.guardian_url:
            self.base_url = config.guardian_url
        else:
            if config.guardian_host.startswith('http://') or config.guardian_host.startswith('https://'):
                self.base_url = config.guardian_host
            else:
                self.base_url = f"http://{config.guardian_host}:{config.guardian_port}"
        
    async def validate_access(self, agent_id: str, agent_card: Dict[str, Any], 
                            request_metadata: Dict[str, Any] = None) -> Dict[str, Any]:
        """Validate agent access via Guardian"""
        import httpx
        
        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    f"{self.base_url}/v1/tools/validate_semantic_access",
                    json={
                        "agent_id": agent_id,
                        "agent_card": agent_card,
                        "request_metadata": request_metadata or {}
                    },
                    timeout=10.0
                )
                
                if response.status_code == 200:
                    return response.json()
                else:
                    logger.error(f"Guardian error: {response.status_code}")
                    return {
                        "allowed": False,
                        "reason": f"Guardian service error: {response.status_code}",
                        "risk_score": 1.0
                    }
                    
        except Exception as e:
            logger.error(f"Error contacting Guardian: {e}")
            return {
                "allowed": False,
                "reason": f"Guardian service unavailable: {str(e)}",
                "risk_score": 1.0
            }

# Initialize guardian client
guardian_client = GuardianClient()
{% endif %}

# Routes
@app.get("/")
async def root():
    """Root endpoint with service information"""
    return {
        "service": "{{ project_name }}",
        "description": "{{ description }}",
        "domain": "{{ domain }}",
        "version": "{{ version | default('0.1.0') }}",
        "status": "running",
        "timestamp": datetime.utcnow().isoformat(),
        "config": {
            "abi_role": config.abi_role,
            "abi_node": config.abi_node,
            "model_name": config.model_name,
            {% if with_semantic_layer %}
            "semantic_layer": f"{config.semantic_layer_host}:{config.semantic_layer_port}",
            {% endif %}
            {% if with_guardian %}
            "guardian_security": f"{config.guardian_host}:{config.guardian_port}",
            {% endif %}
        }
    }

@app.get("/health")
async def health():
    """Health check endpoint"""
    health_status = {
        "status": "healthy",
        "service": "{{ project_name }}",
        "timestamp": datetime.utcnow().isoformat(),
        "checks": {}
    }
    
    {% if with_semantic_layer %}
    # Check semantic layer
    try:
        agents = await semantic_client.list_agents()
        health_status["checks"]["semantic_layer"] = {
            "status": "healthy",
            "registered_agents": len(agents)
        }
    except Exception as e:
        health_status["checks"]["semantic_layer"] = {
            "status": "unhealthy",
            "error": str(e)
        }
        health_status["status"] = "degraded"
    {% endif %}
    
    {% if with_guardian %}
    # Check guardian
    try:
        import httpx
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"http://{config.guardian_host}:{config.guardian_port}/v1/tools/get_guardian_status",
                timeout=5.0
            )
            if response.status_code == 200:
                health_status["checks"]["guardian"] = {
                    "status": "healthy",
                    "details": response.json()
                }
            else:
                health_status["checks"]["guardian"] = {
                    "status": "unhealthy",
                    "error": f"HTTP {response.status_code}"
                }
                health_status["status"] = "degraded"
    except Exception as e:
        health_status["checks"]["guardian"] = {
            "status": "unhealthy",
            "error": str(e)
        }
        health_status["status"] = "degraded"
    {% endif %}
    
    return health_status

@app.get("/v1/config")
async def get_config():
    """Get current configuration"""
    return config.to_dict()

{% if with_semantic_layer %}
@app.get("/v1/agents")
async def list_agents():
    """List all registered agents"""
    try:
        agents = await semantic_client.list_agents()
        return {
            "agents": agents,
            "total": len(agents),
            "timestamp": datetime.utcnow().isoformat()
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error listing agents: {str(e)}")

@app.post("/v1/agents/find", response_model=AgentResponse)
async def find_agent(request: AgentRequest):
    """Find the best agent for a given query"""
    try:
        # Find agent via semantic layer
        agent_card = await semantic_client.find_agent(request.query)
        
        if not agent_card:
            return AgentResponse(
                agent_id=None,
                agent_name=None,
                response=f"No suitable agent found for query: {request.query}",
                metadata={
                    "query": request.query,
                    "found": False,
                    "timestamp": datetime.utcnow().isoformat()
                }
            )
        
        {% if with_guardian %}
        # Validate access via Guardian
        validation_result = await guardian_client.validate_access(
            agent_id=agent_card.get("id", "unknown"),
            agent_card=agent_card,
            request_metadata={
                "query": request.query,
                "method": "find_agent",
                "source_ip": "internal",
                "user_agent": "{{ project_name }}"
            }
        )
        
        if not validation_result.get("allowed", False):
            return AgentResponse(
                agent_id=agent_card.get("id"),
                agent_name=agent_card.get("name"),
                response=f"Access denied by Guardian: {validation_result.get('reason', 'Unknown reason')}",
                metadata={
                    "query": request.query,
                    "found": True,
                    "access_denied": True,
                    "risk_score": validation_result.get("risk_score", 1.0),
                    "guardian_validation": validation_result,
                    "timestamp": datetime.utcnow().isoformat()
                }
            )
        {% endif %}
        
        return AgentResponse(
            agent_id=agent_card.get("id"),
            agent_name=agent_card.get("name"),
            response=f"Found agent: {agent_card.get('name')} - {agent_card.get('description')}",
            metadata={
                "query": request.query,
                "found": True,
                "agent_card": agent_card,
                {% if with_guardian %}
                "guardian_validation": validation_result,
                {% endif %}
                "timestamp": datetime.utcnow().isoformat()
            }
        )
        
    except Exception as e:
        logger.error(f"Error in find_agent: {e}")
        raise HTTPException(status_code=500, detail=f"Error finding agent: {str(e)}")
{% endif %}

{% if domain == 'finance' %}
@app.post("/v1/finance/analyze_risk")
async def analyze_financial_risk(request: dict):
    """Analyze financial risk for a scenario"""
    try:
        scenario = request.get("scenario", "")
        
        {% if with_semantic_layer %}
        # Find finance-specialized agent
        finance_query = f"financial risk analysis {scenario}"
        agent_card = await semantic_client.find_agent(finance_query)
        
        if not agent_card:
            raise HTTPException(status_code=404, detail="No suitable financial analysis agent found")
        
        {% if with_guardian %}
        # Validate with Guardian (finance-specific validation)
        validation_result = await guardian_client.validate_access(
            agent_id=agent_card.get("id", "unknown"),
            agent_card=agent_card,
            request_metadata={
                "tool_name": "analyze_financial_risk",
                "scenario": scenario,
                "compliance_verified": request.get("compliance_verified", False)
            }
        )
        
        if not validation_result.get("allowed", False):
            raise HTTPException(
                status_code=403, 
                detail=f"Access denied: {validation_result.get('reason', 'Unknown reason')}"
            )
        {% endif %}
        {% endif %}
        
        return {
            "scenario": scenario,
            {% if with_semantic_layer %}
            "recommended_agent": agent_card.get('name'),
            "agent_id": agent_card.get('id'),
            {% endif %}
            "risk_analysis_ready": True,
            "compliance_status": "verified" if request.get("compliance_verified") else "pending",
            "timestamp": datetime.utcnow().isoformat()
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error in financial risk analysis: {e}")
        raise HTTPException(status_code=500, detail=f"Error analyzing financial risk: {str(e)}")

@app.post("/v1/finance/compliance_check")
async def compliance_check(request: dict):
    """Check compliance for financial operations"""
    try:
        operation = request.get("operation", "")
        
        {% if with_semantic_layer %}
        # Find compliance agent
        compliance_query = f"compliance regulatory {operation}"
        agent_card = await semantic_client.find_agent(compliance_query)
        
        if not agent_card:
            raise HTTPException(status_code=404, detail="No suitable compliance agent found")
        {% endif %}
        
        return {
            "operation": operation,
            {% if with_semantic_layer %}
            "compliance_agent": agent_card.get('name'),
            "agent_id": agent_card.get('id'),
            {% endif %}
            "regulatory_ready": True,
            "compliance_framework": "{{ compliance_framework | default('SOX, GDPR') }}",
            "timestamp": datetime.utcnow().isoformat()
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error in compliance check: {e}")
        raise HTTPException(status_code=500, detail=f"Error checking compliance: {str(e)}")
{% elif domain == 'healthcare' %}
@app.post("/v1/healthcare/analyze_patient_data")
async def analyze_patient_data(request: dict):
    """Analyze patient data with HIPAA compliance"""
    try:
        data_type = request.get("data_type", "")
        patient_id = request.get("patient_id", "")
        
        {% if with_semantic_layer %}
        # Find healthcare agent
        healthcare_query = f"patient data analysis {data_type} HIPAA compliant"
        agent_card = await semantic_client.find_agent(healthcare_query)
        
        if not agent_card:
            raise HTTPException(status_code=404, detail="No suitable healthcare analysis agent found")
        
        {% if with_guardian %}
        # Validate with Guardian (healthcare-specific validation)
        validation_result = await guardian_client.validate_access(
            agent_id=agent_card.get("id", "unknown"),
            agent_card=agent_card,
            request_metadata={
                "tool_name": "patient_data_analysis",
                "patient_data": {"patient_id": patient_id, "data_type": data_type},
                "hipaa_compliant": True
            }
        )
        
        if not validation_result.get("allowed", False):
            raise HTTPException(
                status_code=403, 
                detail=f"Access denied: {validation_result.get('reason', 'Unknown reason')}"
            )
        {% endif %}
        {% endif %}
        
        return {
            "data_type": data_type,
            "patient_id": patient_id,
            {% if with_semantic_layer %}
            "healthcare_agent": agent_card.get('name'),
            "agent_id": agent_card.get('id'),
            {% endif %}
            "hipaa_compliant": True,
            "privacy_level": "high",
            "audit_required": True,
            "timestamp": datetime.utcnow().isoformat()
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error in patient data analysis: {e}")
        raise HTTPException(status_code=500, detail=f"Error analyzing patient data: {str(e)}")
{% endif %}

{% if with_guardian %}
@app.get("/v1/security/status")
async def get_security_status():
    """Get security status from Guardian"""
    try:
        import httpx
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"http://{config.guardian_host}:{config.guardian_port}/v1/tools/get_security_metrics",
                timeout=10.0
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                raise HTTPException(status_code=response.status_code, detail="Guardian service error")
                
    except Exception as e:
        logger.error(f"Error getting security status: {e}")
        raise HTTPException(status_code=500, detail=f"Error getting security status: {str(e)}")

@app.post("/v1/security/block_agent")
async def block_agent(request: dict):
    """Block an agent via Guardian"""
    try:
        agent_id = request.get("agent_id", "")
        reason = request.get("reason", "Manual block via API")
        
        if not agent_id:
            raise HTTPException(status_code=400, detail="agent_id is required")
        
        import httpx
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"http://{config.guardian_host}:{config.guardian_port}/v1/tools/block_agent",
                json={"agent_id": agent_id, "reason": reason},
                timeout=10.0
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                raise HTTPException(status_code=response.status_code, detail="Guardian service error")
                
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error blocking agent: {e}")
        raise HTTPException(status_code=500, detail=f"Error blocking agent: {str(e)}")
{% endif %}

def main():
    """Main entry point"""
    logger.info(f"🌟 {{ project_name }} starting on {config.agent_host}:{config.agent_port}")
    
    uvicorn.run(
        "main:app",
        host=config.agent_host,
        port=config.agent_port,
        reload=config.debug,
        log_level=config.log_level.lower()
    )

if __name__ == "__main__":
    main()