"""
Appointment scheduler utility to connect conversation state to appointment scheduling
"""

import httpx
import asyncio
import logging
import json
import os
import uuid
from datetime import datetime
from typing import Dict, Any, Optional

from utils.appointment_state import get_appointment_state, complete_appointment_flow

# Set up logger
logger = logging.getLogger("mango_ai_agent")

# Import the appointment service
from services.appointment_service import create_appointment, get_appointment, update_appointment_status

# Log that we're using the service layer
logger.info("Using appointment service layer for scheduling appointments")


async def schedule_appointment_from_state(conversation_id: str) -> Dict[str, Any]:
    """
    Schedule an appointment using the information collected in the conversation state
    
    Args:
        conversation_id: The conversation ID
        
    Returns:
        Dict[str, Any]: The appointment response or error details
    """
    logger.info(f"Attempting to schedule appointment for conversation {conversation_id}")
    try:
        # Get the appointment state
        state = get_appointment_state(conversation_id)
        
        # Check if we have all required information
        if not state:
            logger.error(f"No appointment state found for conversation {conversation_id}")
            return {
                "success": False,
                "error": "No appointment state found",
                "missing_fields": ["name", "email", "phone", "topic"]
            }
            
        if state.get("meeting_request_stage") != "ready_to_schedule":
            missing = state.get("missing_fields", [])
            logger.info(f"Not ready to schedule - missing fields: {missing}")
            return {
                "success": False,
                "error": "Not ready to schedule - missing information",
                "missing_fields": missing,
                "collected_info": state.get("extracted_info", {})
            }
            
        # Extract the information needed for the appointment
        extracted_info = state.get("extracted_info", {})
        
        # Prepare the appointment request
        appointment_request = {
            "name": extracted_info.get("name", ""),
            "email": extracted_info.get("email", ""),
            "phone": extracted_info.get("phone", ""),
            "company": extracted_info.get("company", ""),
            "topic": extracted_info.get("topic", state.get("suggested_topic", "General Consultation")),
            "preferred_date": extracted_info.get("preferred_date", ""),
            "preferred_time": extracted_info.get("preferred_time", ""),
            "additional_notes": extracted_info.get("additional_notes", ""),
            "conversation_id": conversation_id
        }
        
        # Validate phone number format more strictly
        phone = appointment_request.get("phone", "")
        if not validate_phone_number(phone):
            logger.error(f"Invalid phone number format: {phone}")
            return {
                "success": False,
                "error": "Invalid phone number format",
                "details": f"The provided phone number '{phone}' is not valid. Please provide a valid phone number."
            }
        
        # Make multiple attempts to call the API before falling back to direct file saving
        max_retries = 3
        retry_count = 0
        last_error = None
        
        while retry_count < max_retries:
            try:
                # Log detailed API call information
                timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
                logger.info(f"[{timestamp}] API CALL - Attempt {retry_count + 1}/{max_retries} to schedule appointment via API")
                logger.info(f"[{timestamp}] API ENDPOINT: {API_URL}/appointment/schedule")
                
                # Log request details (sanitized to remove sensitive info)
                safe_request = appointment_request.copy()
                if "email" in safe_request:
                    safe_request["email"] = f"{safe_request['email'][:3]}...@{safe_request['email'].split('@')[-1]}"
                if "phone" in safe_request:
                    safe_request["phone"] = f"{safe_request['phone'][:3]}...{safe_request['phone'][-2:]}"
                
                logger.info(f"[{timestamp}] API REQUEST: {json.dumps(safe_request)}")
                logger.info(f"[{timestamp}] CONVERSATION_ID: {conversation_id}")
                
                async with httpx.AsyncClient() as client:
                    # Use the specific appointment endpoint
                    logger.info(f"Making API call to: {APPOINTMENT_ENDPOINT}")
                    logger.info(f"Request payload: {json.dumps(appointment_request)}")
                    
                    response = await client.post(
                        APPOINTMENT_ENDPOINT,
                        json=appointment_request,
                        timeout=10.0
                    )
                    
                    # Log response details
                    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
                    logger.info(f"[{timestamp}] API RESPONSE STATUS: {response.status_code}")
                    
                    if response.status_code == 200:
                        result = response.json()
                        logger.info(f"[{timestamp}] API RESPONSE BODY: {json.dumps(result)}")
                        
                        # Update the appointment state to mark it as scheduled
                        appointment_id = result.get("appointment_id")
                        if appointment_id:
                            complete_appointment_flow(conversation_id, appointment_id)
                            logger.info(f"[{timestamp}] APPOINTMENT SCHEDULED - ID: {appointment_id}, CONVERSATION_ID: {conversation_id}")
                        else:
                            logger.warning(f"[{timestamp}] API RESPONSE MISSING APPOINTMENT_ID")
                        return {
                            "success": True,
                            "appointment_id": appointment_id,
                            "status": result.get("status"),
                            "message": result.get("message"),
                            "method": "api"
                        }
                    else:
                        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
                        error_msg = f"API returned error: {response.status_code} - {response.text}"
                        logger.error(f"[{timestamp}] API ERROR: {error_msg}")
                        logger.error(f"[{timestamp}] CONVERSATION_ID: {conversation_id}")
                        last_error = error_msg
                        retry_count += 1
                        logger.info(f"[{timestamp}] RETRYING in 1 second... (Attempt {retry_count + 1}/{max_retries})")
                        await asyncio.sleep(1)  # Wait before retrying
            except Exception as e:
                timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
                error_msg = f"API call failed: {str(e)}"
                logger.error(f"[{timestamp}] API EXCEPTION: {error_msg}")
                logger.error(f"[{timestamp}] CONVERSATION_ID: {conversation_id}")
                logger.error(f"[{timestamp}] TRACEBACK: {__import__('traceback').format_exc()}")
                last_error = error_msg
                retry_count += 1
                logger.info(f"[{timestamp}] RETRYING in 1 second... (Attempt {retry_count + 1}/{max_retries})")
                await asyncio.sleep(1)  # Wait before retrying
        
        # All API attempts failed, log and fall back to direct file saving as last resort
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        logger.warning(f"[{timestamp}] API FAILURE: All {max_retries} API attempts failed.")
        logger.warning(f"[{timestamp}] LAST ERROR: {last_error}")
        logger.warning(f"[{timestamp}] CONVERSATION_ID: {conversation_id}")
        logger.warning(f"[{timestamp}] FALLBACK: Using direct file saving as last resort")
        result = save_appointment_to_file(appointment_request)
        result["method"] = "file_fallback"
        result["api_error"] = last_error
        return result
                
    except Exception as e:
        logger.error(f"Error in schedule_appointment_from_state: {str(e)}")
        return {
            "success": False,
            "error": f"Exception: {str(e)}"
        }

def validate_phone_number(phone: str) -> bool:
    """
    Validate phone number format more strictly
    
    Args:
        phone: The phone number to validate
        
    Returns:
        bool: True if valid, False otherwise
    """
    if not phone:
        return False
        
    # Remove all non-digit characters
    digits_only = ''.join(filter(str.isdigit, phone))
    
    # Check length (most countries have between 7 and 15 digits)
    if len(digits_only) < 6 or len(digits_only) > 15:
        return False
        
    return True


def save_appointment_to_file(appointment_request: Dict[str, Any]) -> Dict[str, Any]:
    """
    Save an appointment using the appointment service
    
    Args:
        appointment_request: The appointment request data
        
    Returns:
        Dict[str, Any]: The result of the operation
    """
    try:
        # Use the appointment service to create the appointment
        result = create_appointment(appointment_request)
        
        logger.info(f"Appointment saved with ID: {result.get('appointment_id')}")
        
        return result
    except Exception as e:
        logger.error(f"Error saving appointment: {str(e)}")
        return {
            "success": False,
            "error": f"Error saving appointment: {str(e)}"
        }


def schedule_appointment_sync(conversation_id: str) -> Dict[str, Any]:
    """
    Synchronous version of appointment scheduling to avoid event loop issues
    
    Args:
        conversation_id: The conversation ID
        
    Returns:
        Dict[str, Any]: The scheduling result
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
    logger.info(f"[{timestamp}] SYNC SCHEDULING - Starting for conversation {conversation_id}")
    
    try:
        # Get the appointment state
        state = get_appointment_state(conversation_id)
        
        # Check if we have all required information
        if not state:
            logger.error(f"[{timestamp}] SYNC SCHEDULING - No appointment state found for conversation {conversation_id}")
            return {
                "success": False,
                "error": "No appointment state found",
                "missing_fields": ["name", "email", "phone", "topic"]
            }
            
        if state.get("meeting_request_stage") != "ready_to_schedule":
            missing = state.get("missing_fields", [])
            logger.info(f"[{timestamp}] SYNC SCHEDULING - Not ready to schedule - missing fields: {missing}")
            return {
                "success": False,
                "error": "Not ready to schedule - missing information",
                "missing_fields": missing,
                "collected_info": state.get("extracted_info", {})
            }
            
        # Extract the information needed for the appointment
        extracted_info = state.get("extracted_info", {})
        
        # Prepare the appointment request
        appointment_request = {
            "name": extracted_info.get("name", ""),
            "email": extracted_info.get("email", ""),
            "phone": extracted_info.get("phone", ""),
            "company": extracted_info.get("company", ""),
            "topic": extracted_info.get("topic", state.get("suggested_topic", "General Consultation")),
            "preferred_date": extracted_info.get("preferred_date", ""),
            "preferred_time": extracted_info.get("preferred_time", ""),
            "additional_notes": extracted_info.get("additional_notes", ""),
            "conversation_id": conversation_id
        }
        
        # Validate phone number format more strictly
        phone = appointment_request.get("phone", "")
        if not validate_phone_number(phone):
            logger.error(f"[{timestamp}] SYNC SCHEDULING - Invalid phone number format: {phone}")
            return {
                "success": False,
                "error": "Invalid phone number format",
                "details": f"The provided phone number '{phone}' is not valid. Please provide a valid phone number."
            }
        
        # Use the appointment service to save the appointment
        logger.info(f"[{timestamp}] SYNC SCHEDULING - Using appointment service to save appointment")
        
        # Log request details (sanitized)
        safe_request = appointment_request.copy()
        if "email" in safe_request:
            safe_request["email"] = f"{safe_request['email'][:3]}...@{safe_request['email'].split('@')[-1]}"
        if "phone" in safe_request:
            safe_request["phone"] = f"{safe_request['phone'][:3]}...{safe_request['phone'][-2:] if len(safe_request['phone']) > 2 else ''}"
        
        logger.info(f"[{timestamp}] SYNC SCHEDULING - Request payload: {json.dumps(safe_request)}")
        
        try:
            # Use the appointment service to create the appointment
            result = save_appointment_to_file(appointment_request)
            result["method"] = "service_layer"
            
            # Update the appointment state to mark it as scheduled
            appointment_id = result.get("appointment_id")
            if appointment_id and result.get("success"):
                complete_appointment_flow(conversation_id, appointment_id)
                
            logger.info(f"[{timestamp}] SYNC SCHEDULING - Successfully scheduled appointment with ID: {appointment_id}")
            return result
                
        except Exception as e:
            error_msg = f"Error saving appointment: {str(e)}"
            logger.error(f"[{timestamp}] SYNC SCHEDULING - {error_msg}")
            logger.error(f"[{timestamp}] TRACEBACK: {__import__('traceback').format_exc()}")
            
            return {
                "success": False,
                "error": error_msg
            }
            
    except Exception as e:
        logger.error(f"[{timestamp}] SYNC SCHEDULING - Error: {str(e)}")
        logger.error(f"[{timestamp}] TRACEBACK: {__import__('traceback').format_exc()}")
        return {
            "success": False,
            "error": f"Exception in sync scheduling: {str(e)}"
        }


def check_and_schedule_if_ready(conversation_id: str) -> Dict[str, Any]:
    """
    Check if all required information is collected and schedule the appointment if ready
    
    Args:
        conversation_id: The conversation ID
        
    Returns:
        Dict[str, Any]: The scheduling result or None if not ready
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
    logger.info(f"[{timestamp}] APPOINTMENT CHECK - Checking if appointment is ready to schedule for conversation {conversation_id}")
    
    # Get the appointment state
    state = get_appointment_state(conversation_id)
    
    # Check if we're in an appointment flow
    if not state:
        logger.info(f"[{timestamp}] APPOINTMENT CHECK - No appointment state found for conversation {conversation_id}")
        return None
        
    # Log the current state
    extracted_info = state.get('extracted_info', {})
    safe_info = {}
    for key, value in extracted_info.items():
        if key == 'email' and value:
            safe_info[key] = f"{value[:3]}...@{value.split('@')[-1] if '@' in value else ''}" 
        elif key == 'phone' and value:
            safe_info[key] = f"{value[:3]}...{value[-2:] if len(value) > 2 else ''}" 
        else:
            safe_info[key] = value
            
    logger.info(f"[{timestamp}] APPOINTMENT STATE - conversation_id={conversation_id}")
    logger.info(f"[{timestamp}] APPOINTMENT STATE - meeting_request={state.get('meeting_request')}")
    logger.info(f"[{timestamp}] APPOINTMENT STATE - stage={state.get('meeting_request_stage')}")
    logger.info(f"[{timestamp}] APPOINTMENT STATE - missing_fields={state.get('missing_fields')}")
    logger.info(f"[{timestamp}] APPOINTMENT STATE - extracted_info={safe_info}")
               
    # Check if we're ready to schedule
    if (state.get("meeting_request") and 
        state.get("meeting_request_stage") == "ready_to_schedule"):
        
        logger.info(f"[{timestamp}] APPOINTMENT READY - All information collected for conversation {conversation_id}")
        logger.info(f"[{timestamp}] APPOINTMENT TRIGGER - Initiating API call for scheduling")
        
        # Schedule the appointment using a safer async approach
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        logger.info(f"[{timestamp}] SCHEDULING - Setting up appointment scheduling")
        
        try:
            # Instead of trying to create new event loops or run_until_complete,
            # we'll use a direct synchronous approach to avoid event loop conflicts
            logger.info(f"[{timestamp}] SCHEDULING - Calling schedule_appointment_sync")
            result = schedule_appointment_sync(conversation_id)
            
            logger.info(f"[{timestamp}] SCHEDULING RESULT - {json.dumps(result)}")
            return result
        except Exception as e:
            logger.error(f"[{timestamp}] SCHEDULING ERROR - {str(e)}")
            logger.error(f"[{timestamp}] TRACEBACK: {__import__('traceback').format_exc()}")
            return {
                "success": False,
                "error": f"Error in scheduling: {str(e)}"
            }
    
    return None
