#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Dify平台回访应用调用模块
用于调用Dify平台上创建的回访应用API
"""

import json
import requests
import time
from typing import Dict, List, Optional, Any
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class DifyCallbackAPI:
    """Dify回访应用API调用类"""
    
    def __init__(self, api_key: str, base_url: str = "https://dify.lumiidental.com/v1"):
        """
        初始化API调用客户端
        
        Args:
            api_key: Dify API密钥
            base_url: Dify服务器地址，默认为您提供的地址
        """
        self.api_key = api_key
        self.base_url = base_url.rstrip('/')
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
    
    def call_chat_completion(self, patient_data: Dict[str, Any], 
                           conversation_id: str = None,
                           user_id: str = "callback_system",
                           response_mode: str = "blocking",
                           max_retries: int = 3,
                           timeout: int = 60) -> Dict[str, Any]:
        """
        调用Dify聊天完成API生成回访内容
        
        Args:
            patient_data: 患者数据字典
            conversation_id: 会话ID（可选）
            user_id: 用户ID，用于标识调用者
            response_mode: 响应模式，"blocking"或"streaming"
            max_retries: 最大重试次数
            timeout: 请求超时时间（秒）
            
        Returns:
            API响应结果
        """
        # 构建请求数据
        request_data = {
            "inputs": self._build_patient_inputs(patient_data),
            "query": self._build_callback_prompt(patient_data),
            "response_mode": response_mode,
            "user": user_id
        }
        
        if conversation_id:
            request_data["conversation_id"] = conversation_id
        
        url = f"{self.base_url}/chat-messages"
        
        # 重试机制
        for attempt in range(max_retries):
            try:
                logger.info(f"调用Dify聊天API (尝试 {attempt + 1}/{max_retries}): {url}")
                logger.info(f"请求超时设置: {timeout}秒")
                
                response = requests.post(
                    url, 
                    headers=self.headers, 
                    json=request_data, 
                    timeout=timeout
                )
                response.raise_for_status()
                
                result = response.json()
                logger.info("API调用成功")
                return result
                
            except requests.exceptions.Timeout as e:
                logger.warning(f"请求超时 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2  # 递增等待时间
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已超时")
                    raise
                    
            except requests.exceptions.RequestException as e:
                logger.error(f"API调用失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已失败")
                    raise
    
    def call_completion_api(self, patient_data: Dict[str, Any],
                          user_id: str = "callback_system",
                          response_mode: str = "blocking",
                          max_retries: int = 3,
                          timeout: int = 60) -> str:
        """
        调用Dify文本完成API（适用于文本生成应用）
        
        Args:
            patient_data: 患者数据字典
            user_id: 用户ID
            response_mode: 响应模式
            max_retries: 最大重试次数
            timeout: 请求超时时间（秒）
            
        Returns:
            生成的回访话术文本
        """
        # 构建请求数据
        request_data = {
            "inputs": self._build_patient_inputs(patient_data),
            "response_mode": response_mode,
            "user": user_id
        }
        
        url = f"{self.base_url}/completion-messages"
        
        # 重试机制
        for attempt in range(max_retries):
            try:
                logger.info(f"调用Dify完成API (尝试 {attempt + 1}/{max_retries})")
                logger.info(f"请求超时设置: {timeout}秒")
                
                response = requests.post(
                    url, 
                    headers=self.headers, 
                    json=request_data, 
                    timeout=timeout
                )
                response.raise_for_status()
                
                result = response.json()
                logger.info("API调用成功")
                
                # 提取文本内容
                if 'answer' in result:
                    return result['answer']
                elif 'message' in result and 'content' in result['message']:
                    return result['message']['content']
                else:
                    logger.warning("API响应格式异常，返回原始结果")
                    return str(result)
                
            except requests.exceptions.Timeout as e:
                logger.warning(f"请求超时 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已超时")
                    raise
                    
            except requests.exceptions.RequestException as e:
                logger.error(f"API调用失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已失败")
                    raise
        
        return ""
    
    def call_workflow(self, patient_data: Dict[str, Any],
                     user_id: str = "callback_system",
                     response_mode: str = "blocking",
                     max_retries: int = 3,
                     timeout: int = 60) -> Dict[str, Any]:
        """
        调用Dify工作流API
        
        Args:
            patient_data: 患者数据字典
            user_id: 用户ID
            response_mode: 响应模式
            max_retries: 最大重试次数
            timeout: 请求超时时间（秒）
            
        Returns:
            工作流执行结果
        """
        # 构建请求数据
        request_data = {
            "inputs": self._build_patient_inputs(patient_data),
            "response_mode": response_mode,
            "user": user_id
        }
        
        url = f"{self.base_url}/workflows/run"
        
        # 重试机制
        for attempt in range(max_retries):
            try:
                logger.info(f"调用Dify工作流API (尝试 {attempt + 1}/{max_retries})")
                logger.info(f"请求超时设置: {timeout}秒")
                
                response = requests.post(
                    url, 
                    headers=self.headers, 
                    json=request_data, 
                    timeout=timeout
                )
                response.raise_for_status()
                
                result = response.json()
                logger.info("工作流API调用成功")
                return result
                
            except requests.exceptions.Timeout as e:
                logger.warning(f"请求超时 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已超时")
                    raise
                    
            except requests.exceptions.RequestException as e:
                logger.error(f"API调用失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已失败")
                    raise
    
    def call_agent_chat(self, patient_data: Dict[str, Any], 
                       conversation_id: str = None,
                       user_id: str = "callback_system",
                       response_mode: str = "streaming",
                       max_retries: int = 3,
                       timeout: int = 60) -> str:
        """
        调用Dify Agent模式的聊天API
        
        Args:
            patient_data: 患者数据字典
            conversation_id: 会话ID（可选）
            user_id: 用户ID，用于标识调用者
            response_mode: 响应模式，Agent模式必须使用"streaming"
            max_retries: 最大重试次数
            timeout: 请求超时时间（秒）
            
        Returns:
            生成的回访话术文本
        """
        # Agent模式必须使用streaming
        if response_mode != "streaming":
            logger.warning("Agent模式强制使用streaming响应模式")
            response_mode = "streaming"
            
        # 构建请求数据 - Agent模式使用不同的请求格式
        request_data = {
            "query": self._build_callback_prompt(patient_data),
            "inputs": self._build_patient_inputs(patient_data),
            "response_mode": response_mode,
            "user": user_id
        }
        
        if conversation_id:
            request_data["conversation_id"] = conversation_id
        
        # Agent模式使用chat-messages端点
        url = f"{self.base_url}/chat-messages"
        
        # 重试机制
        for attempt in range(max_retries):
            try:
                logger.info(f"调用Dify Agent API (尝试 {attempt + 1}/{max_retries}): {url}")
                logger.info(f"请求超时设置: {timeout}秒")
                
                response = requests.post(
                    url, 
                    headers=self.headers, 
                    json=request_data, 
                    timeout=timeout,
                    stream=True  # 启用流式响应
                )
                response.raise_for_status()
                
                # 处理流式响应
                full_content = ""
                for line in response.iter_lines():
                    if line:
                        line_str = line.decode('utf-8')
                        if line_str.startswith('data: '):
                            try:
                                data_str = line_str[6:]  # 移除 'data: ' 前缀
                                if data_str.strip() == '[DONE]':
                                    break
                                data = json.loads(data_str)
                                if data.get('event') == 'message' and 'answer' in data:
                                    full_content += data['answer']
                                elif data.get('event') == 'agent_message' and 'answer' in data:
                                    full_content += data['answer']
                            except json.JSONDecodeError:
                                continue
                
                logger.info("Agent API调用成功")
                return full_content.strip()
                
            except requests.exceptions.Timeout as e:
                logger.warning(f"请求超时 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2  # 递增等待时间
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已超时")
                    raise
                    
            except requests.exceptions.RequestException as e:
                logger.error(f"API调用失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    wait_time = (attempt + 1) * 2
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    logger.error("所有重试都已失败")
                    raise
        
        return ""
    
    def _build_patient_inputs(self, patient_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        构建患者数据输入参数（使用合并结果数据格式）
        
        Args:
            patient_data: 患者数据（合并结果格式）
            
        Returns:
            格式化的输入参数字典
        """
        from dify_config import map_patient_data
        
        # 使用统一的数据映射
        return map_patient_data(patient_data)
    
    def _build_callback_prompt(self, patient_data: Dict[str, Any]) -> str:
        """
        构建回访提示词
        
        Args:
            patient_data: 患者数据
            
        Returns:
            格式化的提示词
        """
        prompt = f"""
请基于以下患者信息生成专业的回访内容：

患者基本信息：
- 姓名：{patient_data.get('姓名', '未知')}
- 性别：{patient_data.get('性别', '未知')}
- 年龄：{patient_data.get('年龄', '未知')}
- 病历号：{patient_data.get('病历号', '未知')}

就诊信息：
- 最后就诊时间：{patient_data.get('最后一次就诊时间', '未知')}
- 就诊诊所：{patient_data.get('最后一次就诊诊所', '未知')}
- 主治医生：{patient_data.get('最后一次就诊医生', '未知')}
- 上次主诉：{patient_data.get('上次就诊主诉', '未知')}
- 上次诊断：{patient_data.get('上次就诊诊断', '未知')}
- 医生诊断：{patient_data.get('医生诊断', '未知')}
- 上次处置：{patient_data.get('上次处置', '未知')}

漏诊信息：
- 漏诊项目：{patient_data.get('漏诊项', '无')}
- 牙槽骨吸收：{patient_data.get('牙槽骨吸收', '否')}
- 缺失牙：{patient_data.get('缺失牙', '[]')}
- 恒牙萌出空间不足：{patient_data.get('恒牙萌出空间不足', '否')}
- 医嘱：{patient_data.get('医嘱', '未知')}

历史消费：
- 历史结算项目：{patient_data.get('历史结算项目和金额', '无')}
- 诊所收入：{patient_data.get('诊所收入', 0)}

请生成一份专业、温馨的回访内容，包括：
1. 问候语
2. 治疗效果询问
3. 后续护理建议
4. 复诊提醒（如需要）
5. 结束语
"""
        return prompt.strip()
    
    def batch_callback(self, patients_data: List[Dict[str, Any]], 
                      delay: float = 1.0,
                      api_type: str = "chat") -> List[Dict[str, Any]]:
        """
        批量回访处理
        
        Args:
            patients_data: 患者数据列表
            delay: 请求间隔时间（秒）
            api_type: API类型，"chat"、"completion"或"workflow"
            
        Returns:
            回访结果列表
        """
        results = []
        
        for i, patient_data in enumerate(patients_data):
            try:
                logger.info(f"处理第 {i+1}/{len(patients_data)} 个患者: {patient_data.get('客户', '未知')}")
                
                # 根据API类型选择调用方法
                if api_type == "chat":
                    result = self.call_chat_completion(patient_data, timeout=90)
                elif api_type == "completion":
                    callback_text = self.call_completion_api(patient_data, timeout=90)
                    result = {"answer": callback_text}
                elif api_type == "workflow":
                    result = self.call_workflow(patient_data, timeout=90)
                elif api_type == "agent_chat":
                    result = self.call_agent_chat(patient_data, timeout=90)
                else:
                    raise ValueError(f"不支持的API类型: {api_type}")
                
                # 添加患者信息到结果中
                callback_result = {
                    "patient_info": {
                        "name": patient_data.get('客户'),
                        "record_id": patient_data.get('病历号'),
                        "age": patient_data.get('年龄'),
                        "gender": patient_data.get('性别')
                    },
                    "callback_content": result,
                    "api_type": api_type,
                    "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
                }
                
                results.append(callback_result)
                
                # 添加延迟避免频率限制
                if delay > 0 and i < len(patients_data) - 1:
                    logger.info(f"等待 {delay} 秒后处理下一个患者...")
                    time.sleep(delay)
                    
            except Exception as e:
                logger.error(f"处理患者 {patient_data.get('客户', '未知')} 时出错: {e}")
                error_result = {
                    "patient_info": {
                        "name": patient_data.get('客户'),
                        "record_id": patient_data.get('病历号'),
                        "age": patient_data.get('年龄'),
                        "gender": patient_data.get('性别')
                    },
                    "error": str(e),
                    "api_type": api_type,
                    "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
                }
                results.append(error_result)
        
        return results
    
    def save_callback_results(self, results: List[Dict[str, Any]], 
                            filename: str = "dify_callback_results.json"):
        """
        保存回访结果到文件
        
        Args:
            results: 回访结果列表
            filename: 保存文件名
        """
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(results, f, ensure_ascii=False, indent=2)
            logger.info(f"回访结果已保存到: {filename}")
        except Exception as e:
            logger.error(f"保存文件失败: {e}")
            raise
    
    def test_connection(self) -> bool:
        """
        测试与Dify服务器的连接
        
        Returns:
            连接是否成功
        """
        try:
            # 尝试访问基础URL
            response = requests.get(self.base_url, timeout=10)
            if response.status_code == 200:
                logger.info("Dify服务器连接成功")
                return True
            else:
                logger.warning(f"Dify服务器响应异常: {response.status_code}")
                return False
        except Exception as e:
            logger.error(f"无法连接到Dify服务器: {e}")
            return False


def main():
    """主函数 - 示例用法"""
    
    # API配置 - 请替换为您的实际API密钥
    API_KEY = "your_dify_api_key_here"  # 请在这里填入您的Dify API密钥
    BASE_URL = "http://dify.lumiidental.com/v1"
    
    # 初始化API客户端
    api_client = DifyCallbackAPI(API_KEY, BASE_URL)
    
    # 测试连接
    if not api_client.test_connection():
        logger.error("无法连接到Dify服务器，请检查配置")
        return
    
    # 加载患者数据
    try:
        # 尝试加载现有的患者数据文件
        data_files = ['漏诊客户画像.json', 'data/patients/merged/合并结果.json']
        patients_data = None
        
        for file_name in data_files:
            try:
                with open(file_name, 'r', encoding='utf-8') as f:
                    patients_data = json.load(f)
                logger.info(f"成功加载患者数据文件: {file_name}")
                break
            except FileNotFoundError:
                continue
        
        if not patients_data:
            logger.error("未找到患者数据文件")
            return
        
        logger.info(f"加载了 {len(patients_data)} 个患者数据")
        
        # 选择前3个患者进行测试
        test_patients = patients_data[:3]
        
        # 批量处理回访 - 可以选择不同的API类型
        logger.info("开始批量回访处理...")
        
        # 使用聊天完成API
        results = api_client.batch_callback(test_patients, delay=2.0, api_type="chat")
        
        # 保存结果
        api_client.save_callback_results(results, "dify_patient_callback_results.json")
        
        # 打印统计信息
        success_count = sum(1 for r in results if "error" not in r)
        error_count = len(results) - success_count
        
        logger.info(f"回访处理完成:")
        logger.info(f"- 成功: {success_count} 个")
        logger.info(f"- 失败: {error_count} 个")
        
    except Exception as e:
        logger.error(f"处理过程中出错: {e}")


if __name__ == "__main__":
    main() 