#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：keyword_matcher.py
模块描述：关键词提取与元素匹配模块，用于自然语言步骤定位

作者：czj
创建日期：2026-08-05
最后修改：2026-08-05
"""

import logging
import re
from typing import List, Tuple, Optional, Dict, Any

logger = logging.getLogger(__name__)


# ==================== 动作词表 ====================

ACTION_WORDS = [
    # 输入类
    "输入", "填写", "填入", "键入", "写入", "填写", "输入",
    # 点击类
    "点击", "按下", "单击", "双击", "选择",
    # 导航类
    "打开", "导航", "访问", "进入", "跳转", "前往",
    # 等待类
    "等待", "延时", "等待",
    # 验证类
    "断言", "验证", "检查", "确认",
    # 其他操作
    "勾选", "取消", "悬停", "滚动", "截图"
]

# 元素类型词表
ELEMENT_WORDS = [
    "按钮", "输入框", "下拉框", "复选框", "单选框",
    "链接", "菜单", "图标", "标签", "表格", "列表",
    "卡片", "对话框", "抽屉", "弹窗", "导航"
]


# ==================== 关键词提取 ====================

def extract_keywords(description: str) -> List[str]:
    """
    从自然语言描述中提取关键词

    策略：
    1. 去除特殊符号（【】《》等）
    2. 去除动作词和元素类型词
    3. 提取剩余的关键词（名词、修饰词等）
    4. 按 2-gram 分词获取更精确的关键词

    Args:
        description (str): 步骤描述，如 "输入用户名 admin@xty"

    Returns:
        List[str]: 关键词列表，如 ["用户名", "admin", "admin@xty"]

    Example:
        >>> extract_keywords("点击登录按钮")
        ["登录"]
        >>> extract_keywords("输入用户名 admin@xty")
        ["用户名", "admin", "admin@xty"]
        >>> extract_keywords("点击【功能中心】展开")
        ["功能中心"]
    """
    # 去除特殊符号
    cleaned = description
    special_chars = ['【', '】', '《', '》', '「', '」', '『', '』', '〔', '〕', '〈', '〉']
    for ch in special_chars:
        cleaned = cleaned.replace(ch, '')

    # 去除动作词
    for word in sorted(ACTION_WORDS + ELEMENT_WORDS, key=len, reverse=True):
        cleaned = cleaned.replace(word, "")
    cleaned = cleaned.strip()

    # 去除修饰词（这些词不是关键词，但会影响匹配）
    # ⚠️ 注意：'添加'、'新增'、'完成'、'确定'、'取消' 可能是按钮名称，不应移除
    modifier_words = ['展开', '分类', '操作', '查看', '是否', '正确',
                      '条目', '数据', '验证', '成功', '页面', '系统']
    for word in modifier_words:
        cleaned = cleaned.replace(word, "")
    cleaned = cleaned.strip()

    # ⚠️ 关键修复：先提取【】内的核心词（优先级最高）
    core_keywords = []
    bracket_match = re.findall(r'【([^】]+)】', description)
    if bracket_match:
        for match in bracket_match:
            core_keywords.append(match)
            # 添加 2-gram
            for i in range(len(match) - 1):
                sub = match[i:i+2]
                if sub not in ACTION_WORDS and sub not in ELEMENT_WORDS:
                    core_keywords.append(sub)

    keywords = []

    # 添加清理后的关键词
    if cleaned:
        keywords.append(cleaned)

    # 2-gram 分词（提取连续两个字的关键词）
    if len(cleaned) >= 2:
        for i in range(len(cleaned) - 1):
            sub = cleaned[i:i+2]
            if len(sub) == 2 and sub not in ACTION_WORDS and sub not in ELEMENT_WORDS:
                keywords.append(sub)

    # 单字关键词（去掉停用词）
    stopwords = {'的', '在', '是', '和', '有', '等', '中', '为', '了', '与', '或', '、', '，', '。', ' '}
    for ch in cleaned:
        if ch.strip() and ch not in stopwords:
            keywords.append(ch)

    # ⚠️ 【】内的核心词放在最前面（优先级最高）
    result = []
    seen = set()

    # 先添加核心关键词
    for kw in core_keywords:
        if kw not in seen:
            seen.add(kw)
            result.append(kw)

    # 再添加其他关键词
    for kw in keywords:
        if kw not in seen:
            seen.add(kw)
            result.append(kw)

    return result


def extract_value_from_description(description: str) -> Optional[str]:
    """
    从步骤描述中提取操作值

    例如："输入用户名 admin@xty" -> "admin@xty"
    例如："输入账号：admin@xty" -> "admin@xty"
    例如："输入密码：Ubains@13579" -> "Ubains@13579"
    例如："输入参考价值：100" -> "100"

    Args:
        description (str): 步骤描述

    Returns:
        Optional[str]: 提取的值，未找到返回 None
    """
    # 匹配模式1：动作 + 目标 + 冒号 + 值（中文冒号）
    # 例如："输入账号：admin@xty" -> "admin@xty"
    match = re.search(r'(?:输入|填写|填入|键入|写入)\s*[^：:]*[：:]\s*([\w@.\-]+)\s*$', description)
    if match:
        return match.group(1)

    # 匹配模式2：动作 + 目标 + 空格 + 值
    # 例如："输入用户名 admin@xty" -> "admin@xty"
    match = re.search(r'(?:输入|填写|填入|键入|写入)\s*.*?\s+([\w@.\-]+)\s*$', description)
    if match:
        return match.group(1)

    # 匹配模式3：值在引号中
    match = re.search(r'["\']([^"\']+)["\']', description)
    if match:
        return match.group(1)

    return None


def detect_action_type(description: str) -> str:
    """
    根据描述推断动作类型

    Args:
        description (str): 步骤描述

    Returns:
        str: 动作类型 (navigate/click/fill/wait/select/assert)
    """
    desc_lower = description.lower()

    # 导航
    if any(kw in desc_lower for kw in ['访问', '打开', '导航', '进入', '跳转', '前往']):
        return 'navigate'

    # 输入
    if any(kw in desc_lower for kw in ['输入', '填写', '填入', '键入', '写入']):
        return 'fill'

    # 选择
    if any(kw in desc_lower for kw in ['选择', '下拉']):
        return 'select'

    # 等待
    if any(kw in desc_lower for kw in ['等待', '延时']):
        return 'wait'

    # 验证（优先级提高）
    if any(kw in desc_lower for kw in ['断言', '验证', '检查', '确认', '查看', '是否', '是否成功']):
        return 'assert'

    # 默认为点击
    return 'click'


def is_verification_step(description: str) -> bool:
    """
    判断是否为验证类步骤（需要检查操作结果提示）

    验证类步骤特征：
    - 包含"查看"、"检查"、"验证"等关键词
    - 包含"是否成功"、"是否正确"等疑问句式
    - 包含"新增成功"、"添加成功"等期望结果

    Args:
        description (str): 步骤描述

    Returns:
        bool: 是否为验证类步骤
    """
    verification_keywords = [
        '查看', '检查', '验证', '确认', '判断',
        '是否成功', '是否正确', '是否新增',
        '新增成功', '添加成功', '保存成功', '删除成功',
        '操作成功', '提交成功', '创建成功',
        '列表是否', '数据是否'
    ]

    for kw in verification_keywords:
        if kw in description:
            return True

    return False


# ==================== 元素匹配 ====================

def match_element_by_keywords(
    page,
    keywords: List[str],
    action: str,
    timeout: int = 5000,
    max_candidates: int = 10
) -> Tuple[Optional[Any], List[Dict[str, Any]]]:
    """
    通过关键词在页面元素中直接匹配

    三级匹配策略：
    1. 精确匹配：ID, name, data-testid
    2. 包含匹配：placeholder, aria-label, text
    3. 回退策略：根据动作类型推断

    Args:
        page: Playwright Page 对象
        keywords (List[str]): 关键词列表
        action (str): 动作类型
        timeout (int): 超时时间（毫秒）
        max_candidates (int): 最大返回候选数量

    Returns:
        Tuple[Optional[Any], List[Dict]]: (元素对象列表, 候选选择器列表)
            元素对象列表按置信度降序排列（最多 max_candidates 个）
            候选选择器列表按置信度降序排列
    """
    candidates = []

    # 获取所有可交互元素（包含主页面 + iframe/微前端）
    try:
        # 扩展元素查询范围，包含 Element Plus 组件和常见可点击元素
        base_selector = (
            'input:visible, button:visible, a:visible, select:visible, textarea:visible, '
            # 语义化 role 元素
            '[role="button"]:visible, [role="link"]:visible, [role="checkbox"]:visible, '
            '[role="radio"]:visible, [role="tab"]:visible, [role="menuitem"]:visible, '
            # Element Plus 组件
            '.el-button:visible, .el-checkbox:visible, .el-tabs__item:visible, '
            # 常见可点击元素（图标、自定义按钮）
            'i[onclick]:visible, div[onclick]:visible, span[onclick]:visible, '
            'div[class*="btn"]:visible, span[class*="btn"]:visible, '
            # 微前端中的常见可点击元素
            '.block:visible, p:visible'
        )

        elements = page.locator(base_selector).all()
        total_elements = len(elements)

        # 🔧 新增：在所有 iframe 中查找元素
        for frame in page.frames:
            if frame == page.main_frame:
                continue
            try:
                frame_elements = frame.locator(base_selector).all()
                elements.extend(frame_elements)
                if frame_elements:
                    logger.debug(f"在 iframe 中找到 {len(frame_elements)} 个元素")
            except Exception as e:
                logger.debug(f"iframe 元素查询失败（忽略）: {e}")

    except Exception as e:
        logger.warning(f"获取页面元素失败: {e}")
        return None, []

    logger.info(f"页面找到 {len(elements)} 个可交互元素（主页面 {total_elements} + iframe {len(elements) - total_elements}），关键词: {keywords}")

    for el in elements:
        try:
            # 提取元素属性
            tag = el.evaluate('el => el.tagName')
            el_type = el.get_attribute('type') or ''
            placeholder = el.get_attribute('placeholder') or ''
            # 扩展文本提取范围，支持 div/span 等可点击元素
            text_extractable_tags = ['BUTTON', 'A', 'DIV', 'SPAN', 'I', 'LABEL', 'LI']
            text = el.inner_text().strip() if tag in text_extractable_tags else ''
            el_id = el.get_attribute('id') or ''
            name = el.get_attribute('name') or ''
            aria_label = el.get_attribute('aria-label') or ''
            data_testid = el.get_attribute('data-testid') or el.get_attribute('data-test-id') or ''
            class_name = el.get_attribute('class') or ''

            score = 0.0
            selectors = []

            # 1. ID 匹配（最高优先级）
            if el_id:
                for kw in keywords:
                    if kw.lower() in el_id.lower():
                        score += 0.4
                        selectors.append({
                            'type': 'css',
                            'value': f'#{el_id}',
                            'confidence': 0.95,
                            'priority': 1
                        })

            # 2. data-testid 匹配（高优先级）
            if data_testid:
                for kw in keywords:
                    if kw.lower() in data_testid.lower():
                        score += 0.35
                        selectors.append({
                            'type': 'css',
                            'value': f'[data-testid="{data_testid}"]',
                            'confidence': 0.90,
                            'priority': 2
                        })

            # 3. placeholder 匹配（输入框）
            if placeholder and tag == 'INPUT':
                for kw in keywords:
                    if kw.lower() in placeholder.lower():
                        score += 0.3
                        selectors.append({
                            'type': 'css',
                            'value': f'input[placeholder*="{placeholder}"]',
                            'confidence': 0.85,
                            'priority': 3
                        })

            # 4. aria-label 匹配
            if aria_label:
                for kw in keywords:
                    if kw.lower() in aria_label.lower():
                        score += 0.3
                        selectors.append({
                            'type': 'css',
                            'value': f'[aria-label*="{aria_label}"]',
                            'confidence': 0.80,
                            'priority': 4
                        })

            # 5. 文本匹配（按钮、链接、可点击的 div/span）
            # ⚠️ 扩展：允许 div、span、i、label、li 等元素进行文本匹配
            text_matchable_tags = ['BUTTON', 'A', 'DIV', 'SPAN', 'I', 'LABEL', 'LI']
            if text and tag in text_matchable_tags:
                for kw in keywords:
                    if kw.lower() in text.lower():
                        score += 0.25
                        # 根据元素类型调整选择器
                        if tag in ['BUTTON', 'A']:
                            selector_value = f'{tag.lower()}:has-text("{text}")'
                        else:
                            selector_value = f'{tag.lower()}:visible:has-text("{text}")'
                        selectors.append({
                            'type': 'css',
                            'value': selector_value,
                            'confidence': 0.75,
                            'priority': 5
                        })

            # 6. name 匹配
            if name:
                for kw in keywords:
                    if kw.lower() in name.lower():
                        score += 0.2
                        selectors.append({
                            'type': 'css',
                            'value': f'[name="{name}"]',
                            'confidence': 0.70,
                            'priority': 6
                        })

            # 7. 动作类型加分/减分
            if action == 'fill' and tag in ['INPUT', 'TEXTAREA']:
                score += 0.20
            # ⚠️ click 操作额外加分标签扩展
            elif action == 'click' and tag in ['BUTTON', 'A', 'I', 'DIV', 'SPAN', 'LI']:
                score += 0.25
            elif action == 'select' and tag == 'SELECT':
                score += 0.20

            # ⚠️ 关键修复：点击操作不应该匹配输入框（除非关键词明确包含输入相关）
            if action == 'click' and tag in ['INPUT', 'TEXTAREA']:
                # 只有关键词明确包含输入相关词汇时才保留输入框
                input_keywords = ['输入框', '输入', '框', '填写', 'input']
                if not any(kw in input_keywords for kw in keywords):
                    score *= 0.3  # 大幅降低分数，让按钮优先

            # 填充操作不应该匹配按钮（除非关键词明确包含按钮相关）
            if action == 'fill' and tag in ['BUTTON', 'A']:
                fill_keywords = ['按钮', '点击', 'click']
                if not any(kw in fill_keywords for kw in keywords):
                    score *= 0.3  # 大幅降低分数

            # 8. 类型匹配（password, email, tel 等）
            if el_type:
                if action == 'fill':
                    if el_type == 'password' and any(kw in '密码' for kw in keywords):
                        score += 0.2
                        selectors.append({
                            'type': 'css',
                            'value': 'input[type="password"]',
                            'confidence': 0.85,
                            'priority': 3
                        })

            if score > 0.15 and selectors:
                # 按优先级排序选择器
                selectors.sort(key=lambda x: x['priority'])
                candidates.append({
                    'element': el,
                    'score': score,
                    'selectors': selectors,
                    'info': {
                        'tag': tag,
                        'type': el_type,
                        'placeholder': placeholder,
                        'text': text,
                        'id': el_id
                    }
                })

        except Exception as e:
            logger.debug(f"处理元素时出错（跳过）: {e}")
            continue

    # 按分数降序排序
    candidates.sort(key=lambda x: x['score'], reverse=True)

    if not candidates:
        return None, []

    # 限制候选数量
    limited_candidates = candidates[:max_candidates]

    # 返回所有候选元素和选择器（供 Claude 语义排序使用）
    elements_list = [c['element'] for c in limited_candidates]
    all_selectors = []
    for c in limited_candidates:
        all_selectors.extend(c['selectors'])

    # 去重选择器
    seen_selectors = set()
    unique_selectors = []
    for sel in all_selectors:
        if sel['value'] not in seen_selectors:
            seen_selectors.add(sel['value'])
            unique_selectors.append(sel)

    # 日志
    best = limited_candidates[0]
    logger.info(f"最佳匹配元素: {best['info']}, 分数: {best['score']:.2f}, 候选数: {len(limited_candidates)}")

    return elements_list, unique_selectors


def get_candidate_details(
    page,
    elements: List[Any]
) -> List[Dict[str, Any]]:
    """
    获取候选元素的详细信息（供 Claude 语义分析使用）

    Args:
        page: Playwright Page 对象
        elements: 元素对象列表

    Returns:
        List[Dict]: 候选元素详情列表，格式：
            [
                {
                    "index": 0,
                    "tag": "BUTTON",
                    "text": "新建会议",
                    "selector": "button:has-text('新建会议')",
                    "attributes": {...},
                    "position": {"x": 100, "y": 200, "width": 80, "height": 32}
                },
                ...
            ]
    """
    candidates = []

    for idx, el in enumerate(elements):
        try:
            # 提取元素属性
            tag = el.evaluate('el => el.tagName')
            text = ""
            try:
                text = el.inner_text().strip()[:100]  # 限制长度
            except Exception:
                pass

            # 提取关键属性
            el_id = el.get_attribute('id') or ''
            el_class = el.get_attribute('class') or ''
            el_type = el.get_attribute('type') or ''
            placeholder = el.get_attribute('placeholder') or ''
            aria_label = el.get_attribute('aria-label') or ''
            name = el.get_attribute('name') or ''
            data_testid = el.get_attribute('data-testid') or el.get_attribute('data-test-id') or ''

            # 获取元素位置
            position = {}
            try:
                box = el.bounding_box()
                if box:
                    position = {
                        'x': int(box.get('x', 0)),
                        'y': int(box.get('y', 0)),
                        'width': int(box.get('width', 0)),
                        'height': int(box.get('height', 0))
                    }
            except Exception:
                pass

            # 构建选择器（优先级：ID > data-testid > class > text）
            selector = ""
            if el_id:
                selector = f'#{el_id}'
            elif data_testid:
                selector = f'[data-testid="{data_testid}"]'
            elif el_class and len(el_class.split()) > 0:
                selector = f'.{el_class.split()[0]}'
            elif text:
                selector = f'{tag.lower()}:has-text("{text[:30]}")'
            else:
                selector = tag.lower()

            # 构建候选元素信息
            candidate = {
                'index': idx,
                'tag': tag,
                'text': text,
                'selector': selector,
                'attributes': {
                    'id': el_id,
                    'class': el_class,
                    'type': el_type,
                    'placeholder': placeholder,
                    'aria-label': aria_label,
                    'name': name,
                    'data-testid': data_testid
                },
                'position': position
            }

            candidates.append(candidate)

        except Exception as e:
            logger.debug(f"获取元素详情失败（跳过）: {e}")
            continue

    return candidates


def find_element_by_semantic(
    page,
    keywords: List[str],
    action: str,
    timeout: int = 5000
) -> Tuple[Optional[Any], List[Dict[str, Any]]]:
    """
    通过语义推断匹配元素（当关键词无法直接匹配时）

    根据动作类型推断目标元素类型：
    - fill + 有 value -> 找输入框
    - click + 包含"按钮" -> 找按钮
    - click + 包含"菜单" -> 找菜单项
    - wait + 包含"页面" -> 找容器元素

    Args:
        page: Playwright Page 对象
        keywords (List[str]): 关键词列表
        action (str): 动作类型
        timeout (int): 超时时间（毫秒）

    Returns:
        Tuple[Optional[Any], List[Dict]]: (元素对象, 候选选择器列表)
    """
    logger.info(f"语义推断匹配: action={action}, keywords={keywords}")

    # fill 动作：找输入框
    if action == 'fill':
        try:
            # 优先找可见的输入框
            inputs = page.locator('input:visible, textarea:visible').all()
            if inputs:
                # 如果只有一个输入框，直接返回
                if len(inputs) == 1:
                    return inputs[0], [{
                        'type': 'css',
                        'value': 'input:visible',
                        'confidence': 0.70,
                        'priority': 1
                    }]

                # 多个输入框时，优先找 type=text 或 placeholder 包含关键词的
                for inp in inputs:
                    inp_type = inp.get_attribute('type') or 'text'
                    placeholder = inp.get_attribute('placeholder') or ''

                    if inp_type in ['text', 'email', 'tel', '']:
                        if any(kw.lower() in placeholder.lower() for kw in keywords):
                            return inp, [{
                                'type': 'css',
                                'value': f'input[placeholder*="{placeholder}"]',
                                'confidence': 0.80,
                                'priority': 1
                            }]

                # 默认返回第一个输入框
                return inputs[0], [{
                    'type': 'css',
                    'value': 'input:visible',
                    'confidence': 0.60,
                    'priority': 1
                }]
        except Exception as e:
            logger.warning(f"语义推断查找输入框失败: {e}")

    # click 动作：找按钮
    if action == 'click':
        # 如果描述包含"按钮"，优先找按钮
        if any('按钮' in kw or 'button' in kw.lower() for kw in keywords):
            try:
                buttons = page.locator('button:visible').all()
                if buttons:
                    # 找文本匹配的按钮
                    for btn in buttons:
                        text = btn.inner_text().strip()
                        if any(kw.lower() in text.lower() for kw in keywords):
                            return btn, [{
                                'type': 'css',
                                'value': f'button:has-text("{text}")',
                                'confidence': 0.80,
                                'priority': 1
                            }]

                    # 默认返回第一个按钮
                    return buttons[0], [{
                        'type': 'css',
                        'value': 'button:visible',
                        'confidence': 0.60,
                        'priority': 1
                    }]
            except Exception as e:
                logger.warning(f"语义推断查找按钮失败: {e}")

        # 如果描述包含"菜单"或"导航"，找菜单项
        if any('菜单' in kw or '导航' in kw or 'menu' in kw.lower() for kw in keywords):
            try:
                menu_items = page.locator('[role="menuitem"]:visible, .el-menu-item:visible').all()
                if menu_items:
                    for item in menu_items:
                        text = item.inner_text().strip()
                        if any(kw in text for kw in keywords):
                            return item, [{
                                'type': 'css',
                                'value': f'[role="menuitem"]:has-text("{text}"), .el-menu-item:has-text("{text}")',
                                'confidence': 0.75,
                                'priority': 1
                            }]
            except Exception as e:
                logger.warning(f"语义推断查找菜单失败: {e}")

        # ⚠️ 新增：如果描述包含"图标"或"icon"，查找 i 元素
        if any('图标' in kw or 'icon' in kw.lower() for kw in keywords):
            try:
                icon_elements = page.locator('i:visible, .icon:visible').all()
                if icon_elements:
                    for icon in icon_elements:
                        aria_label = icon.get_attribute('aria-label') or ''
                        title = icon.get_attribute('title') or ''
                        class_name = icon.get_attribute('class') or ''
                        icon_info = f"{aria_label} {title} {class_name}"
                        if any(kw.lower() in icon_info.lower() for kw in keywords):
                            return icon, [{
                                'type': 'css',
                                'value': f'i.{class_name.split()[0]}' if class_name else 'i',
                                'confidence': 0.70,
                                'priority': 1
                            }]
                # 回退：返回第一个可见图标
                if icon_elements:
                    return icon_elements[0], [{
                        'type': 'css',
                        'value': 'i:visible',
                        'confidence': 0.60,
                        'priority': 1
                    }]
            except Exception as e:
                logger.warning(f"语义推断查找图标失败: {e}")

        # ⚠️ 新增：如果描述包含"复选框"或"勾选"，查找 checkbox
        if any('复选框' in kw or '勾选' in kw or 'checkbox' in kw.lower() for kw in keywords):
            try:
                checkboxes = page.locator('.el-checkbox:visible, [role="checkbox"]:visible').all()
                if checkboxes:
                    for cb in checkboxes:
                        text = cb.inner_text().strip()
                        if any(kw in text for kw in keywords):
                            return cb, [{
                                'type': 'css',
                                'value': f'.el-checkbox:has-text("{text}")',
                                'confidence': 0.75,
                                'priority': 1
                            }]
                if checkboxes:
                    return checkboxes[0], [{
                        'type': 'css',
                        'value': '.el-checkbox:visible',
                        'confidence': 0.60,
                        'priority': 1
                    }]
            except Exception as e:
                logger.warning(f"语义推断查找复选框失败: {e}")

        # ⚠️ 新增：如果描述包含"按钮"或"button"，找所有可见按钮（包括 Element Plus）
        if any('按钮' in kw or 'button' in kw.lower() for kw in keywords):
            try:
                buttons = page.locator('button:visible, .el-button:visible').all()
                if buttons:
                    for btn in buttons:
                        text = btn.inner_text().strip()
                        if any(kw.lower() in text.lower() for kw in keywords):
                            return btn, [{
                                'type': 'css',
                                'value': f'button:has-text("{text}")',
                                'confidence': 0.80,
                                'priority': 1
                            }]
                    return buttons[0], [{
                        'type': 'css',
                        'value': 'button:visible',
                        'confidence': 0.60,
                        'priority': 1
                    }]
            except Exception as e:
                logger.warning(f"语义推断查找Element Plus按钮失败: {e}")

    # wait 动作：找容器元素
    if action == 'wait':
        container_selectors = [
            '.container', '.el-main', '.main', '#app',
            '[class*="content"]', '[class*="page"]'
        ]
        for sel in container_selectors:
            try:
                el = page.locator(sel).first
                if el:
                    return el, [{
                        'type': 'css',
                        'value': sel,
                        'confidence': 0.50,
                        'priority': 1
                    }]
            except Exception:
                continue

    return None, []