import asyncio
import os
import sys

# 尽量统一控制台编码为 utf-8，避免中文输出报错
try:
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")
    if hasattr(sys.stderr, "reconfigure"):
        sys.stderr.reconfigure(encoding="utf-8")
except Exception:
    pass

# 确保项目根目录在 sys.path 中，以便导入 src.*
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if PROJECT_ROOT not in sys.path:
    sys.path.append(PROJECT_ROOT)

try:
    # 显式从 src.chat.knowledge.lpmm_ops 导入单例对象
    from src.chat.knowledge.lpmm_ops import lpmm_ops
    from src.common.logger import get_logger
    from src.memory_system.retrieval_tools.query_lpmm_knowledge import query_lpmm_knowledge
    from src.chat.knowledge import lpmm_start_up
    from src.config.config import global_config
except ImportError as e:
    print(f"导入失败，请确保在项目根目录下运行脚本: {e}")
    sys.exit(1)

logger = get_logger("lpmm_interactive_manager")


async def interactive_add():
    """交互式导入知识"""
    print("\n" + "=" * 40)
    print("      --- 📥 导入知识 (Add) ---")
    print("=" * 40)
    print("说明：请输入要导入的文本内容。")
    print("      - 支持多段落，段落间请保留空行。")
    print("      - 输入完成后，在新起的一行输入 'EOF' 并回车结束输入。")
    print("-" * 40)

    lines = []
    while True:
        try:
            line = input()
            if line.strip().upper() == "EOF":
                break
            lines.append(line)
        except EOFError:
            break

    text = "\n".join(lines).strip()
    if not text:
        print("\n[!] 内容为空，操作已取消。")
        return

    print("\n[进度] 正在调用 LPMM 接口进行信息抽取与向量化，请稍候...")
    try:
        # 使用 lpmm_ops.py 中的接口
        result = await lpmm_ops.add_content(text)

        if result["status"] == "success":
            print(f"\n[√] 成功：{result['message']}")
            print(f"    实际新增段落数: {result.get('count', 0)}")
        else:
            print(f"\n[×] 失败：{result['message']}")
    except Exception as e:
        print(f"\n[×] 发生异常: {e}")
        logger.error(f"add_content 异常: {e}", exc_info=True)


async def interactive_delete():
    """交互式删除知识"""
    print("\n" + "=" * 40)
    print("      --- 🗑️ 删除知识 (Delete) ---")
    print("=" * 40)
    print("删除模式：")
    print("  1. 关键词模糊匹配（删除包含关键词的所有段落）")
    print("  2. 完整文段匹配（删除完全匹配的段落）")
    print("-" * 40)

    mode = input("请选择删除模式 (1/2): ").strip()
    exact_match = False

    if mode == "2":
        exact_match = True
        print("\n[完整文段匹配模式]")
        print("说明：请输入要删除的完整文段内容（必须完全一致）。")
        print("      - 支持多行输入，输入完成后在新起的一行输入 'EOF' 并回车。")
        print("-" * 40)
        lines = []
        while True:
            try:
                line = input()
                if line.strip().upper() == "EOF":
                    break
                lines.append(line)
            except EOFError:
                break
        keyword = "\n".join(lines).strip()
    else:
        if mode != "1":
            print("\n[!] 无效选择，默认使用关键词模糊匹配模式。")
        print("\n[关键词模糊匹配模式]")
        keyword = input("请输入匹配关键词: ").strip()

    if not keyword:
        print("\n[!] 输入为空，操作已取消。")
        return

    print("-" * 40)
    confirm = (
        input(f"危险确认：确定要删除所有匹配 '{keyword[:50]}{'...' if len(keyword) > 50 else ''}' 的知识吗？(y/N): ")
        .strip()
        .lower()
    )
    if confirm != "y":
        print("\n[!] 已取消删除操作。")
        return

    print("\n[进度] 正在执行删除并更新索引...")
    try:
        # 使用 lpmm_ops.py 中的接口
        result = await lpmm_ops.delete(keyword, exact_match=exact_match)

        if result["status"] == "success":
            print(f"\n[√] 成功：{result['message']}")
            print(f"    删除条数: {result.get('deleted_count', 0)}")
        elif result["status"] == "info":
            print(f"\n[i] 提示：{result['message']}")
        else:
            print(f"\n[×] 失败：{result['message']}")
    except Exception as e:
        print(f"\n[×] 发生异常: {e}")
        logger.error(f"delete 异常: {e}", exc_info=True)


async def interactive_clear():
    """交互式清空知识库"""
    print("\n" + "=" * 40)
    print("      --- ⚠️ 清空知识库 (Clear All) ---")
    print("=" * 40)
    print("警告：此操作将删除LPMM知识库中的所有内容！")
    print("      - 所有段落向量")
    print("      - 所有实体向量")
    print("      - 所有关系向量")
    print("      - 整个知识图谱")
    print("      - 此操作不可恢复！")
    print("-" * 40)

    # 双重确认
    confirm1 = input("⚠️  第一次确认：确定要清空整个知识库吗？(输入 'YES' 继续): ").strip()
    if confirm1 != "YES":
        print("\n[!] 已取消清空操作。")
        return

    print("\n" + "=" * 40)
    confirm2 = input("⚠️  第二次确认：此操作不可恢复，请再次输入 'CLEAR' 确认: ").strip()
    if confirm2 != "CLEAR":
        print("\n[!] 已取消清空操作。")
        return

    print("\n[进度] 正在清空知识库...")
    try:
        # 使用 lpmm_ops.py 中的接口
        result = await lpmm_ops.clear_all()

        if result["status"] == "success":
            print(f"\n[√] 成功：{result['message']}")
            stats = result.get("stats", {})
            before = stats.get("before", {})
            after = stats.get("after", {})
            print("\n[统计信息]")
            print(
                f"  清空前: 段落={before.get('paragraphs', 0)}, 实体={before.get('entities', 0)}, "
                f"关系={before.get('relations', 0)}, KG节点={before.get('kg_nodes', 0)}, KG边={before.get('kg_edges', 0)}"
            )
            print(
                f"  清空后: 段落={after.get('paragraphs', 0)}, 实体={after.get('entities', 0)}, "
                f"关系={after.get('relations', 0)}, KG节点={after.get('kg_nodes', 0)}, KG边={after.get('kg_edges', 0)}"
            )
        else:
            print(f"\n[×] 失败：{result['message']}")
    except Exception as e:
        print(f"\n[×] 发生异常: {e}")
        logger.error(f"clear_all 异常: {e}", exc_info=True)


async def interactive_search():
    """交互式查询知识"""
    print("\n" + "=" * 40)
    print("      --- 🔍 查询知识 (Search) ---")
    print("=" * 40)
    print("说明：输入查询问题或关键词，系统会返回相关的知识段落。")
    print("-" * 40)

    # 确保 LPMM 已初始化
    if not global_config.lpmm_knowledge.enable:
        print("\n[!] 警告：LPMM 知识库在配置中未启用。")
        return

    try:
        lpmm_start_up()
    except Exception as e:
        print(f"\n[!] LPMM 初始化失败: {e}")
        logger.error(f"LPMM 初始化失败: {e}", exc_info=True)
        return

    query = input("请输入查询问题或关键词: ").strip()

    if not query:
        print("\n[!] 查询内容为空，操作已取消。")
        return

    # 询问返回条数
    print("-" * 40)
    limit_str = input("希望返回的相关知识条数（默认3，直接回车使用默认值）: ").strip()
    try:
        limit = int(limit_str) if limit_str else 3
        limit = max(1, min(limit, 20))  # 限制在1-20之间
    except ValueError:
        limit = 3
        print("[!] 输入无效，使用默认值 3。")

    print("\n[进度] 正在查询知识库...")
    try:
        result = await query_lpmm_knowledge(query, limit=limit)

        print("\n" + "=" * 60)
        print("[查询结果]")
        print("=" * 60)
        print(result)
        print("=" * 60)
    except Exception as e:
        print(f"\n[×] 查询失败: {e}")
        logger.error(f"查询异常: {e}", exc_info=True)


async def main():
    """主循环"""
    while True:
        print("\n" + "╔" + "═" * 38 + "╗")
        print("║      LPMM 知识库交互管理工具        ║")
        print("╠" + "═" * 38 + "╣")
        print("║  1. 导入知识 (Add Content)          ║")
        print("║  2. 删除知识 (Delete Content)       ║")
        print("║  3. 查询知识 (Search Content)       ║")
        print("║  4. 清空知识库 (Clear All) ⚠️        ║")
        print("║  0. 退出 (Exit)                     ║")
        print("╚" + "═" * 38 + "╝")

        choice = input("请选择操作编号: ").strip()

        if choice == "1":
            await interactive_add()
        elif choice == "2":
            await interactive_delete()
        elif choice == "3":
            await interactive_search()
        elif choice == "4":
            await interactive_clear()
        elif choice in ("0", "q", "Q", "quit", "exit"):
            print("\n已退出工具。")
            break
        else:
            print("\n[!] 无效的选择，请输入 0, 1, 2, 3 或 4。")


if __name__ == "__main__":
    try:
        # 运行主循环
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n\n[!] 用户中断程序 (Ctrl+C)。")
    except Exception as e:
        print(f"\n[!] 程序运行出错: {e}")
        logger.error(f"Main loop 异常: {e}", exc_info=True)
