from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from retell import Retell
import os
import sys
import logging
from pydantic import BaseModel
from typing import Dict, Optional, List
from datetime import datetime, timezone
import httpx
from bson import ObjectId

# Configure logger
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

# Add root directory to Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))

from utils.database import DatabaseManager

app = FastAPI(title="Agent Service")

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

# Initialize database and Retell client
db = DatabaseManager()
agents_collection = db.get_collection("ai_assistants")

# Retell API configuration DONOT CHANGE IT
RETELL_API_KEY = os.getenv("RETELL_API_KEY")
logger.info(f"RETELL_API_KEY: {RETELL_API_KEY}")

RETELL_API_BASE = "https://api.retellai.com"
#https://api.retellai.com/create-agent
class AgentCreate(BaseModel):
    name: str
    gender: str
    language: str
    personality: str
    system_prompt: str
    voice_id: str = "eleven_multilingual_v2"

class PhoneNumberImport(BaseModel):
    phone_number: str  # E.164 format (+country code, then number with no space)
    termination_uri: str  # SIP trunk URI (ends with .pstn.twilio.com for Twilio)
    sip_trunk_auth_username: Optional[str] = None  # Optional SIP trunk authentication
    sip_trunk_auth_password: Optional[str] = None  # Optional SIP trunk authentication
    inbound_agent_id: Optional[str] = None  # Agent ID for inbound calls
    outbound_agent_id: Optional[str] = None  # Agent ID for outbound calls
    nickname: Optional[str] = None  # Optional nickname for reference

# New models for templates
class AgentTemplate(BaseModel):
    name: str
    gender: str
    language: str
    personality: str
    system_prompt: str
    voice_id: str = "eleven_multilingual_v2"
    description: str
    category: str
    
    class Config:
        json_encoders = {
            ObjectId: str
        }

class AgentFromTemplate(BaseModel):
    template_id: str
    business_id: str
    custom_name: Optional[str] = None
    custom_prompt: Optional[str] = None

# Initialize template collection
agent_templates_collection = db.get_collection("agent_templates")

@app.on_event("shutdown")
async def shutdown_event():
    db.close()
########################################## CREATE AGENT ####################################################
@app.post("/agents/create")
async def create_agent(agent: AgentCreate, business_id: str):
    try:
        headers = {
            "Authorization": f"Bearer {RETELL_API_KEY}",
            "Content-Type": "application/json"
        }

        # Prepare agent configuration
        agent_data = {
            "response_engine": {
                "type": "retell-llm",
                "llm_id": "llm_2738593b49dd221fe37ea73f774e"
            },
            "voice_id": agent.voice_id,
            "agent_name": agent.name,
            "system_prompt": agent.system_prompt,
            "voice_temperature": 0.5,
            "responsiveness": 0.4,
            "interruption_sensitivity": 0.5,
            "enable_backchannel": True,
            "backchannel_frequency": 0.7,
            "backchannel_words": [
                "yes",
                "ok"
            ],
            "reminder_trigger_ms": 2000,
            "reminder_max_count": 2,
            "ambient_sound": "summer-outdoor",
            "ambient_sound_volume": 0.5,
            "language": agent.language,
            "webhook_url": "https://webhook.com",
            "enable_transcription_formatting": True,
            "opt_out_sensitive_data_storage": True,
            "normalize_for_speech": True,
            "end_call_after_silence_ms": 60000,
            "post_call_analysis_data": [
                {
                "type": "string",
                "name": "schedule_date",
                "description": "extract if there is some booking schedule in the call",
                "examples": [
                    "I want to book an appointment on March 23rd at 5pm"
                ]
                }
            ],
            "begin_message_delay_ms": 200
        }

        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{RETELL_API_BASE}/create-agent",
                json=agent_data,
                headers=headers
            )
            
            if response.status_code not in [200, 201]:
                raise HTTPException(
                    status_code=response.status_code,
                    detail=f"Retell API error: {response.text}"
                )

            agent_response = response.json()

            # Store in MongoDB
            agent_doc = {
                "business_id": business_id,
                "name": agent.name,
                "gender": agent.gender,
                "language": agent.language, 
                "personality": agent.personality,
                "bio": agent.system_prompt,
                "retell_agent_id": agent_response["agent_id"],
                "config": agent_data,
                "created_at": datetime.now(timezone.utc)
            }
            result = agents_collection.insert_one(agent_doc)
            
            return {
                "message": "Agent created successfully",
                "agent_id": str(result.inserted_id),
                "retell_agent_id": agent_response["agent_id"]
            }
            
    except httpx.RequestError as e:
        raise HTTPException(status_code=500, detail=f"API request failed: {str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/agents/create-from-template")
async def create_agent_from_template(template_data: AgentFromTemplate):
    try:
        # Get template from database
        template = agent_templates_collection.find_one({"_id": ObjectId(template_data.template_id)})
        if not template:
            raise HTTPException(status_code=404, detail="Template not found")

        # Create agent data from template
        agent = AgentCreate(
            name=template_data.custom_name or template["name"],
            gender=template["gender"],
            language=template["language"],
            personality=template["personality"],
            system_prompt=template_data.custom_prompt or template["system_prompt"],
            voice_id=template["voice_id"]
        )

        # Use existing create_agent method
        return await create_agent(agent, business_id=template_data.business_id)

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/voices")
async def list_voices():
    """List all available Retell voices"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{RETELL_API_BASE}/list-voices",
                headers={
                    "Authorization": f"Bearer {RETELL_API_KEY}",
                    "Content-Type": "application/json"
                }
            )
            
            if response.status_code != 200:
                raise HTTPException(
                    status_code=response.status_code, 
                    detail=f"Retell API error: {response.text}"
                )

            voices = response.json()
            return {
                "voices": voices,
                "count": len(voices)
            }

    except httpx.RequestError as e:
        raise HTTPException(status_code=500, detail=f"API request failed: {str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/llms")
async def list_llms():
    """List all available Retell LLMs"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{RETELL_API_BASE}/list-retell-llms",
                headers={
                    "Authorization": f"Bearer {RETELL_API_KEY}",
                    "Content-Type": "application/json"
                }
            )
            logger.info(f"Response: {response.json()}")
            if response.status_code != 200:
                raise HTTPException(
                    status_code=response.status_code,
                    detail=f"Retell API error: {response.text}"
                )

            llms = response.json()
            return {
                "llms": llms,
                "count": len(llms)
            }
            
    except httpx.RequestError as e:
        raise HTTPException(status_code=500, detail=f"API request failed: {str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/phone-numbers/import")
async def import_phone_number(phone_number: PhoneNumberImport):
    """Import a phone number and bind it to agent(s)"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{RETELL_API_BASE}/import-phone-number",
                headers={
                    "Authorization": f"Bearer {RETELL_API_KEY}",
                    "Content-Type": "application/json"
                },
                json={
                    "phone_number": phone_number.phone_number,
                    "termination_uri": phone_number.termination_uri,
                    "sip_trunk_auth_username": phone_number.sip_trunk_auth_username,
                    "sip_trunk_auth_password": phone_number.sip_trunk_auth_password,
                    "inbound_agent_id": phone_number.inbound_agent_id,
                    "outbound_agent_id": phone_number.outbound_agent_id,
                    "nickname": phone_number.nickname
                }
            )

            if response.status_code != 201:
                raise HTTPException(
                    status_code=response.status_code,
                    detail=f"Retell API error: {response.text}"
                )

            phone_number_response = response.json()
            #logger.info(f"Phone number response: {phone_number_response}")
            # Store in MongoDB
            phone_doc = {
                "phone_number": phone_number_response["phone_number"],
                "inbound_agent_id": phone_number_response["inbound_agent_id"],
                "outbound_agent_id": phone_number_response["outbound_agent_id"],
                "nickname": phone_number_response["nickname"],
                "created_at": datetime.now(timezone.utc)
            }
            
            result = db.get_collection("phone_numbers").insert_one(phone_doc)
            logger.info(f"=-=-=-=-=Phone number inserted: {phone_doc}")
            return {
                "message": "Phone number imported successfully",
                "phone_id": str(result.inserted_id),
                "phone_number": phone_number_response
            }
            
    except httpx.RequestError as e:
        raise HTTPException(status_code=500, detail=f"API request failed: {str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

###################### TEMPLATE MANAGEMENT ENDPOINTS ######################

@app.post("/templates/create")
async def create_template(template: AgentTemplate):
    """Create a new agent template"""
    try:
        template_doc = {
            "name": template.name,
            "gender": template.gender,
            "language": template.language,
            "personality": template.personality,
            "system_prompt": template.system_prompt,
            "voice_id": template.voice_id,
            "description": template.description,
            "category": template.category,
            "created_at": datetime.now(timezone.utc)
        }
        
        result = agent_templates_collection.insert_one(template_doc)
        return {
            "message": "Agent template created successfully",
            "template_id": str(result.inserted_id)
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/templates")
async def list_templates(
    language: Optional[str] = None,
    category: Optional[str] = None
):
    """List all agent templates with optional filters"""
    try:
        query = {}
        if language:
            query["language"] = language
        if category:
            query["category"] = category
            
        templates = list(agent_templates_collection.find(query))
        # Convert ObjectId to string for JSON serialization
        for template in templates:
            template["_id"] = str(template["_id"])
            
        return {
            "templates": templates,
            "count": len(templates)
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# @app.post("/agents/from-template")
# async def create_agent_from_template(agent: AgentFromTemplate):
#     """Create a new agent instance from a template"""
#     try:
#         # Get template
#         template = agent_templates_collection.find_one({"_id": ObjectId(agent.template_id)})
#         if not template:
#             raise HTTPException(status_code=404, detail="Template not found")

#         # Prepare agent configuration
#         agent_data = {
#             "response_engine": {
#                 "type": "retell-llm",
#                 "llm_id": "llm_2738593b49dd221fe37ea73f774e"
#             },
#             "voice_id": template["voice_id"],
#             "agent_name": agent.custom_name or template["name"],
#             "system_prompt": agent.custom_prompt or template["system_prompt"],
#             "voice_temperature": 0.5,
#             "responsiveness": 0.4,
#             "interruption_sensitivity": 0.5,
#             "enable_backchannel": True,
#             "backchannel_frequency": 0.7,
#             "backchannel_words": ["yes", "ok"],
#             "reminder_trigger_ms": 2000,
#             "reminder_max_count": 2,
#             "ambient_sound": "summer-outdoor",
#             "ambient_sound_volume": 0.5,
#             "language": template["language"],
#             "webhook_url": "https://webhook.com",
#             "enable_transcription_formatting": True,
#             "opt_out_sensitive_data_storage": True,
#             "normalize_for_speech": True,
#             "end_call_after_silence_ms": 60000,
#             "begin_message_delay_ms": 200
#         }

#         # Create agent on Retell
#         headers = {
#             "Authorization": f"Bearer {RETELL_API_KEY}",
#             "Content-Type": "application/json"
#         }

#         async with httpx.AsyncClient() as client:
#             response = await client.post(
#                 f"{RETELL_API_BASE}/create-agent",
#                 json=agent_data,
#                 headers=headers
#             )
            
#             if response.status_code not in [200, 201]:
#                 raise HTTPException(
#                     status_code=response.status_code,
#                     detail=f"Retell API error: {response.text}"
#                 )

#             agent_response = response.json()

#             # Store in MongoDB
#             agent_doc = {
#                 "name": agent.custom_name or template["name"],
#                 "template_id": ObjectId(agent.template_id),
#                 "business_id": ObjectId(agent.business_id),
#                 "gender": template["gender"],
#                 "language": template["language"],
#                 "personality": template["personality"],
#                 "bio": agent.custom_prompt or template["system_prompt"],
#                 "retell_agent_id": agent_response["agent_id"],
#                 "config": agent_data,
#                 "created_at": datetime.now(timezone.utc)
#             }
            
#             result = agents_collection.insert_one(agent_doc)
            
#             return {
#                 "message": "Agent created successfully",
#                 "agent_id": str(result.inserted_id),
#                 "retell_agent_id": agent_response["agent_id"]
#             }
            
#     except httpx.RequestError as e:
#         raise HTTPException(status_code=500, detail=f"API request failed: {str(e)}")
#     except Exception as e:
#         raise HTTPException(status_code=500, detail=str(e))

# Your existing AI assistant routes here
# ... (previous AI assistant routes code) ... 