"""
数据可视化 Agent：用 Python 代码对 DataFrame 做统计分析和绑图。
"""

import os
import sys
import traceback
import warnings
from io import StringIO
from contextlib import redirect_stdout

# 确保父目录可导入（支持直接运行 python agents/viz_agent.py）
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from langchain.tools import tool
from langchain.agents import create_agent

from config import llm, engine

warnings.filterwarnings("ignore")

# ============================================================
# 1. 中文字体配置
# ============================================================
plt.rcParams["font.sans-serif"] = ["SimHei", "PingFang SC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False

# ============================================================
# 2. 延迟加载 DataFrame（避免 import 时就连库）
# ============================================================
_dataframes = None


def load_dataframes():
    """从数据库加载 DataFrame。首次调用后缓存，后续直接返回缓存。"""
    global _dataframes
    if _dataframes is None:
        _dataframes = {
            "employees_df": pd.read_sql("SELECT * FROM employees", engine),
            "products_df":  pd.read_sql("SELECT * FROM products", engine),
            "orders_df":    pd.read_sql("SELECT * FROM orders", engine),
        }
    return _dataframes


# ============================================================
# 3. 代码执行沙箱
# ============================================================
@tool
def execute_python_code(code: str) -> str:
    """
    执行 Python 代码进行数据分析和可视化。

    可用变量：
      - employees_df: 员工表 DataFrame（字段：id, name, department, salary, hire_date）
      - products_df:  产品表 DataFrame（字段：id, product_name, category, price, stock）
      - orders_df:    订单表 DataFrame（字段：id, employee_id, product_id, quantity, order_date）
      - pd:   pandas 库
      - plt:  matplotlib.pyplot
      - sns:  seaborn
      - np:   numpy

    使用示例：
      result = employees_df.groupby('department')['salary'].mean()
      print(result)
    """
    dfs = load_dataframes()
    sandbox = {
        **dfs,
        "pd":  pd,
        "plt": plt,
        "sns": sns,
        "np":  np,
    }
    exec_locals = {}
    output_buffer = StringIO()

    try:
        with redirect_stdout(output_buffer):
            exec(code, sandbox, exec_locals)
        result = output_buffer.getvalue()
        if not result.strip():
            result = "✅ 代码执行成功（无文本输出，可能已生成图表）"
        return f"执行成功：\n{result}"
    except Exception as e:
        return f"❌ 执行出错：{e}\n\n{traceback.format_exc()}"


# ============================================================
# 4. Agent System Prompt
# ============================================================
VISUALIZATION_PROMPT = """你是一名资深数据分析师，精通 Python、Pandas 和 Matplotlib 数据可视化。

## 可用数据
1. employees_df — 员工表（字段：id, name, department, salary, hire_date）
2. products_df  — 产品表（字段：id, product_name, category, price, stock）
3. orders_df    — 订单表（字段：id, employee_id, product_id, quantity, order_date）

## 工作流程
1. 理解用户的分析需求
2. 用 execute_python_code 工具编写并执行 Python 代码
3. 先做数据探索（head、describe、info），再做深入分析
4. 用中文解释分析结果，给出业务洞察

## 代码规范
- 绑图前设置中文字体：plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC', 'DejaVu Sans']
- 设置 plt.rcParams['axes.unicode_minus'] = False
- 图表尺寸统一用 plt.figure(figsize=(10, 6))
- 必须添加标题、坐标轴标签，让图表自解释
- 用 print() 输出关键统计量，不要只画图不说话
- 图表标题用英文（避免渲染问题），但用中文向用户解释结果

## 注意事项
- 每次只执行一段完整的代码，不要拆成多段
- 先探索数据结构，再做分析——不要上来就画图
- 结果要有业务洞察，不只是"最大值是 XXX"
"""

# ============================================================
# 5. 创建 Agent
# ============================================================
visualization_agent = create_agent(
    model=llm,
    tools=[execute_python_code],
    system_prompt=VISUALIZATION_PROMPT,
)


if __name__ == "__main__":
    dfs = load_dataframes()
    print("✅ 数据加载完成")
    for name, df in dfs.items():
        print(f"   {name}：{len(df)} 行 × {len(df.columns)} 列")
    print("\n✅ 数据可视化 Agent 创建完成")
