"""
对话流节点

用于对话流模式的智能体，支持与用户的交互式对话
"""
import logging

from ..base import BaseNode, NodeContext, NodeResult
from ..registry import NodeRegistry

logger = logging.getLogger(__name__)


@NodeRegistry.register
class QuestionNode(BaseNode):
    """
    问答节点
    
    向用户提出问题，等待用户输入回答
    支持输入验证和默认值
    """
    
    node_type = 'question'
    node_name = '问答节点'
    node_category = 'dialog'
    
    inputs = {
        'question': {
            'type': 'string',
            'description': '要向用户提出的问题',
            'required': True,
        },
        'variable_name': {
            'type': 'string',
            'description': '存储用户回答的变量名',
            'required': True,
        },
        'input_type': {
            'type': 'string',
            'description': '输入类型：text/number/email/phone/date',
            'default': 'text',
        },
        'placeholder': {
            'type': 'string',
            'description': '输入框占位文本',
            'default': '',
        },
        'default_value': {
            'type': 'string',
            'description': '默认值',
            'default': '',
        },
        'required': {
            'type': 'boolean',
            'description': '是否必填',
            'default': True,
        },
        'validation_regex': {
            'type': 'string',
            'description': '验证正则表达式',
            'default': '',
        },
        'validation_message': {
            'type': 'string',
            'description': '验证失败提示',
            'default': '输入格式不正确',
        },
        'render_input': {
            'type': 'boolean',
            'description': '是否渲染输入框，默认不渲染（用户直接在聊天框输入）',
            'default': False,
        },
    }
    
    outputs = {
        'answer': {
            'type': 'string',
            'description': '用户的回答',
        },
        'is_valid': {
            'type': 'boolean',
            'description': '回答是否有效',
        },
    }
    
    def execute(self, context: NodeContext) -> NodeResult:
        """
        执行问答节点
        
        这个节点会暂停工作流执行，等待用户输入
        """
        question = self.config.get('question', '')
        variable_name = self.config.get('variable_name', 'user_input')
        input_type = self.config.get('input_type', 'text')
        placeholder = self.config.get('placeholder', '')
        default_value = self.config.get('default_value', '')
        required = self.config.get('required', True)
        validation_regex = self.config.get('validation_regex', '')
        validation_message = self.config.get('validation_message', '输入格式不正确')
        render_input = self.config.get('render_input', False)
        
        # 解析模板变量
        question = context.resolve_template(question)
        placeholder = context.resolve_template(placeholder)
        default_value = context.resolve_template(default_value)
        
        # 检查是否已有用户输入（续流时）
        user_input = context.variables.get('__user_input__')
        
        if user_input is not None:
            # 用户已输入，验证并继续
            import re
            
            # 将非字符串输入转换为字符串
            if not isinstance(user_input, str):
                user_input = str(user_input)
            
            is_valid = True
            
            # 必填验证
            if required and not user_input.strip():
                is_valid = False
            
            # 正则验证
            if is_valid and validation_regex:
                if not re.match(validation_regex, user_input):
                    is_valid = False
            
            # 类型验证
            if is_valid and input_type == 'number':
                try:
                    user_input = float(user_input)
                except ValueError:
                    is_valid = False
            elif is_valid and input_type == 'email':
                email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
                if not re.match(email_regex, user_input):
                    is_valid = False
            elif is_valid and input_type == 'phone':
                phone_regex = r'^1[3-9]\d{9}$'
                if not re.match(phone_regex, user_input):
                    is_valid = False
            
            if is_valid:
                return NodeResult(
                    success=True,
                    output={
                        'answer': user_input,
                        'is_valid': True,
                    },
                    output_variables={
                        variable_name: user_input,
                    },
                )
            else:
                # 验证失败，重新等待输入
                return NodeResult(
                    success=True,
                    output={
                        'answer': '',
                        'is_valid': False,
                    },
                    waiting_for_input=True,
                    waiting_config={
                        'type': 'question',
                        'question': question,
                        'input_type': input_type,
                        'placeholder': placeholder,
                        'default_value': default_value,
                        'required': required,
                        'error_message': validation_message,
                        'render_input': render_input,
                    },
                )
        else:
            # 首次执行，等待用户输入
            return NodeResult(
                success=True,
                output={
                    'answer': '',
                    'is_valid': False,
                },
                waiting_for_input=True,
                waiting_config={
                    'type': 'question',
                    'question': question,
                    'input_type': input_type,
                    'placeholder': placeholder,
                    'default_value': default_value,
                    'required': required,
                    'render_input': render_input,
                },
            )


@NodeRegistry.register
class ChoiceNode(BaseNode):
    """
    选项节点
    
    向用户展示多个选项，用户选择后继续执行
    支持单选和多选
    """
    
    node_type = 'choice'
    node_name = '选项节点'
    node_category = 'dialog'
    
    inputs = {
        'question': {
            'type': 'string',
            'description': '问题或提示文本',
            'required': True,
        },
        'variable_name': {
            'type': 'string',
            'description': '存储用户选择的变量名',
            'required': True,
        },
        'options': {
            'type': 'array',
            'description': '选项列表',
            'required': True,
            'items': {
                'type': 'object',
                'properties': {
                    'value': {'type': 'string', 'description': '选项值'},
                    'label': {'type': 'string', 'description': '显示文本'},
                    'description': {'type': 'string', 'description': '选项描述'},
                },
            },
        },
        'multiple': {
            'type': 'boolean',
            'description': '是否多选',
            'default': False,
        },
        'min_select': {
            'type': 'integer',
            'description': '最少选择数量',
            'default': 1,
        },
        'max_select': {
            'type': 'integer',
            'description': '最多选择数量',
            'default': 1,
        },
    }
    
    outputs = {
        'selected': {
            'type': 'any',
            'description': '用户选择的值（单选为字符串，多选为数组）',
        },
        'selected_labels': {
            'type': 'any',
            'description': '用户选择的显示文本',
        },
    }
    
    def execute(self, context: NodeContext) -> NodeResult:
        """
        执行选项节点
        """
        question = self.config.get('question', '')
        variable_name = self.config.get('variable_name', 'user_choice')
        options = self.config.get('options', [])
        multiple = self.config.get('multiple', False)
        min_select = self.config.get('min_select', 1)
        max_select = self.config.get('max_select', 1)
        
        # 解析模板变量
        question = context.resolve_template(question)
        
        # 检查是否已有用户选择
        user_selection = context.variables.get('__user_input__')
        
        if user_selection is not None:
            # 用户已选择
            if multiple:
                # 多选：user_selection 应该是数组
                if isinstance(user_selection, str):
                    user_selection = [user_selection]
                elif not isinstance(user_selection, list):
                    # 如果不是字符串也不是列表（比如布尔值），转换为字符串后放入列表
                    user_selection = [str(user_selection)]
                
                # 验证所有选项值是否有效
                valid_values = [opt.get('value') for opt in options]
                invalid_selections = [val for val in user_selection if val not in valid_values]
                
                if invalid_selections:
                    # 有无效选项，重新显示选择界面
                    return NodeResult(
                        success=True,
                        output={'selected': [], 'selected_labels': []},
                        waiting_for_input=True,
                        waiting_config={
                            'type': 'choice',
                            'question': question,
                            'options': options,
                            'multiple': multiple,
                            'min_select': min_select,
                            'max_select': max_select,
                            'error_message': '请从选项中选择',
                        },
                    )
                
                # 验证选择数量
                if len(user_selection) < min_select or len(user_selection) > max_select:
                    return NodeResult(
                        success=True,
                        output={'selected': [], 'selected_labels': []},
                        waiting_for_input=True,
                        waiting_config={
                            'type': 'choice',
                            'question': question,
                            'options': options,
                            'multiple': multiple,
                            'min_select': min_select,
                            'max_select': max_select,
                            'error_message': f'请选择 {min_select}-{max_select} 个选项',
                        },
                    )
                
                # 获取选中的标签
                selected_labels = []
                for opt in options:
                    if opt.get('value') in user_selection:
                        selected_labels.append(opt.get('label', opt.get('value')))
                
                return NodeResult(
                    success=True,
                    output={
                        'selected': user_selection,
                        'selected_labels': selected_labels,
                    },
                    output_variables={
                        variable_name: user_selection,
                        f'{variable_name}_labels': selected_labels,
                    },
                )
            else:
                # 单选：验证选项值是否有效
                valid_values = [opt.get('value') for opt in options]
                if user_selection not in valid_values:
                    # 无效选项，重新显示选择界面
                    return NodeResult(
                        success=True,
                        output={'selected': None, 'selected_labels': None},
                        waiting_for_input=True,
                        waiting_config={
                            'type': 'choice',
                            'question': question,
                            'options': options,
                            'multiple': multiple,
                            'min_select': min_select,
                            'max_select': max_select,
                            'error_message': '请从选项中选择',
                        },
                    )
                
                selected_label = ''
                for opt in options:
                    if opt.get('value') == user_selection:
                        selected_label = opt.get('label', opt.get('value'))
                        break
                
                return NodeResult(
                    success=True,
                    output={
                        'selected': user_selection,
                        'selected_labels': selected_label,
                    },
                    output_variables={
                        variable_name: user_selection,
                        f'{variable_name}_label': selected_label,
                    },
                )
        else:
            # 首次执行，等待用户选择
            return NodeResult(
                success=True,
                output={
                    'selected': None,
                    'selected_labels': None,
                },
                waiting_for_input=True,
                waiting_config={
                    'type': 'choice',
                    'question': question,
                    'options': options,
                    'multiple': multiple,
                    'min_select': min_select,
                    'max_select': max_select,
                },
            )


@NodeRegistry.register
class MessageNode(BaseNode):
    """
    消息节点
    
    向用户发送消息，不等待回复
    """
    
    node_type = 'message'
    node_name = '消息节点'
    node_category = 'dialog'
    
    inputs = {
        'content': {
            'type': 'string',
            'description': '消息内容',
            'required': True,
        },
        'message_type': {
            'type': 'string',
            'description': '消息类型：text/markdown/html',
            'default': 'text',
        },
    }
    
    outputs = {
        'sent': {
            'type': 'boolean',
            'description': '是否发送成功',
        },
    }
    
    def execute(self, context: NodeContext) -> NodeResult:
        """
        执行消息节点
        """
        import logging
        logger = logging.getLogger(__name__)
        
        content = self.config.get('content', '')
        message_type = self.config.get('message_type', 'text')
        
        logger.info(f'[MessageNode] Original content: {content}')
        logger.info(f'[MessageNode] Context variables: item={context.get_variable("item")}, index={context.get_variable("index")}')
        
        # 解析模板变量
        content = context.resolve_template(content)
        
        logger.info(f'[MessageNode] Resolved content: {content}')
        
        return NodeResult(
            success=True,
            output={
                'sent': True,
                'content': content,  # 也在 output 中返回消息内容
            },
            # 发送消息事件
            events=[{
                'type': 'message',
                'content': content,
                'message_type': message_type,
            }],
        )


@NodeRegistry.register
class ConfirmNode(BaseNode):
    """
    确认节点
    
    向用户展示确认对话框，等待用户确认或取消
    """
    
    node_type = 'confirm'
    node_name = '确认节点'
    node_category = 'dialog'
    
    # 扩展的确认关键词列表（覆盖常见表达）
    CONFIRM_KEYWORDS = {
        # 英文
        'true', 'yes', 'ok', 'okay', 'sure', 'confirm', 'confirmed', 'agree', 'accept', 'y',
        # 中文
        '是', '是的', '对', '对的', '好', '好的', '行', '行的', '可以', '没问题', '没有问题',
        '同意', '确认', '确定', '嗯', '嗯嗯', '好吧', '可', '中', '成', '得', '要', '要的',
        '继续', '执行', '进行', '开始', '去吧', '做吧', '干吧',
        # 数字
        '1',
    }
    
    # 扩展的取消关键词列表
    CANCEL_KEYWORDS = {
        # 英文
        'false', 'no', 'cancel', 'reject', 'decline', 'deny', 'n', 'nope',
        # 中文
        '否', '不', '不是', '不行', '不可以', '不要', '不用', '取消', '拒绝', '算了',
        '停止', '终止', '放弃', '别', '别了', '不了', '不用了', '不需要',
        # 数字
        '0',
    }
    
    inputs = {
        'title': {
            'type': 'string',
            'description': '确认框标题',
            'default': '确认',
        },
        'content': {
            'type': 'string',
            'description': '确认内容',
            'required': True,
        },
        'confirm_text': {
            'type': 'string',
            'description': '确认按钮文本',
            'default': '确认',
        },
        'cancel_text': {
            'type': 'string',
            'description': '取消按钮文本',
            'default': '取消',
        },
        'variable_name': {
            'type': 'string',
            'description': '存储结果的变量名',
            'default': 'confirmed',
        },
        'use_llm_intent': {
            'type': 'boolean',
            'description': '使用 LLM 进行意图识别（当关键词匹配失败时）',
            'default': False,
        },
        'llm_model_id': {
            'type': 'string',
            'description': '用于意图识别的 LLM 模型 ID',
            'default': '',
        },
    }
    
    outputs = {
        'confirmed': {
            'type': 'boolean',
            'description': '用户是否确认',
        },
    }
    
    def _match_keywords(self, user_input) -> tuple[bool, bool]:
        """
        使用关键词匹配判断用户意图
        
        Returns:
            (matched, confirmed): matched 表示是否匹配到关键词，confirmed 表示是否确认
        """
        # 布尔值特殊处理（必须在字符串处理之前）
        if user_input is True or user_input == True:
            return True, True
        if user_input is False or user_input == False:
            return True, False
        
        # 确保是字符串
        if not isinstance(user_input, str):
            user_input = str(user_input)
        
        # 标准化输入：去除空格、转小写
        normalized = user_input.strip().lower()
        
        # 精确匹配
        if normalized in self.CONFIRM_KEYWORDS:
            return True, True
        if normalized in self.CANCEL_KEYWORDS:
            return True, False
        
        return False, False
    
    def _llm_intent_recognition(self, user_input: str, context_content: str, model_id: str) -> bool:
        """
        使用 LLM 进行意图识别
        
        Returns:
            confirmed: 用户是否确认
        """
        try:
            from ai_platform.services.llm_service import LLMService
            
            system_prompt = """你是一个意图识别助手。用户正在回应一个确认请求，你需要判断用户的回复是"确认"还是"取消"。

规则：
1. 如果用户表达同意、肯定、愿意继续的意思，返回 "confirm"
2. 如果用户表达拒绝、否定、不愿意继续的意思，返回 "cancel"
3. 如果无法判断，默认返回 "cancel"

只返回 "confirm" 或 "cancel"，不要返回其他内容。"""

            user_prompt = f"""确认请求内容：{context_content}

用户回复：{user_input}

请判断用户意图："""

            llm_service = LLMService()
            response = llm_service.chat(
                model_id=model_id,
                messages=[
                    {'role': 'system', 'content': system_prompt},
                    {'role': 'user', 'content': user_prompt},
                ],
                temperature=0,
                max_tokens=10,
            )
            
            result = response.content.strip().lower()
            return result == 'confirm'
            
        except Exception as e:
            logger.warning(f'LLM 意图识别失败，回退到默认行为: {e}')
            return False
    
    def execute(self, context: NodeContext) -> NodeResult:
        """
        执行确认节点
        """
        title = self.config.get('title', '确认')
        content = self.config.get('content', '')
        confirm_text = self.config.get('confirm_text', '确认')
        cancel_text = self.config.get('cancel_text', '取消')
        variable_name = self.config.get('variable_name', 'confirmed')
        use_llm_intent = self.config.get('use_llm_intent', False)
        llm_model_id = self.config.get('llm_model_id', '')
        
        # 解析模板变量
        title = context.resolve_template(title)
        content = context.resolve_template(content)
        
        # 检查是否已有用户选择
        user_input = context.variables.get('__user_input__')
        
        if user_input is not None:
            # 首先尝试关键词匹配
            matched, confirmed = self._match_keywords(user_input)
            
            if not matched and use_llm_intent and llm_model_id:
                # 关键词未匹配，使用 LLM 意图识别
                logger.info(f'关键词未匹配，使用 LLM 意图识别: {user_input}')
                confirmed = self._llm_intent_recognition(str(user_input), content, llm_model_id)
            elif not matched:
                # 关键词未匹配且未启用 LLM，默认为取消
                logger.info(f'关键词未匹配，默认取消: {user_input}')
                confirmed = False
            
            return NodeResult(
                success=True,
                output={
                    'confirmed': confirmed,
                },
                output_variables={
                    variable_name: confirmed,
                },
            )
        else:
            # 等待用户确认
            return NodeResult(
                success=True,
                output={
                    'confirmed': False,
                },
                waiting_for_input=True,
                waiting_config={
                    'type': 'confirm',
                    'title': title,
                    'content': content,
                    'confirm_text': confirm_text,
                    'cancel_text': cancel_text,
                },
            )
