# coding: utf-8
"""
使用 pyecharts 定制绘图模块

"""

from pyecharts import options as opts
from pyecharts.charts import HeatMap, Kline, Line, Bar, Scatter, Grid, Boxplot
from pyecharts.commons.utils import JsCode
from typing import TYPE_CHECKING, List, Optional
import numpy as np
from czsc.py.enum import Operate
from .ta import SMA, MACD

if TYPE_CHECKING:
    from lightweight_charts import Chart



def kline_pro(
    kline: List[dict],
    fx: List[dict] = [],
    bi: List[dict] = [],
    xd: List[dict] = [],
    bs: List[dict] = [],
    title: str = "缠中说禅K线分析",
    t_seq: List[int] = [],
    width: str = "1400px",
    height: str = "580px",
) -> Grid:
    """绘制缠中说禅K线分析结果

    :param kline: K线
    :param fx: 分型识别结果
    :param bi: 笔识别结果
        {'dt': Timestamp('2020-11-26 00:00:00'),
          'fx_mark': 'd',
          'start_dt': Timestamp('2020-11-25 00:00:00'),
          'end_dt': Timestamp('2020-11-27 00:00:00'),
          'fx_high': 144.87,
          'fx_low': 138.0,
          'bi': 138.0}
    :param xd: 线段识别结果
    :param bs: 买卖点
    :param title: 图表标题
    :param t_seq: 均线系统
    :param width: 图表宽度
    :param height: 图表高度
    :return: 用Grid组合好的图表
    """
    # 配置项设置
    # ------------------------------------------------------------------------------------------------------------------
    bg_color = "#1f212d"  # 背景
    up_color = "#F9293E"
    down_color = "#00aa3b"

    init_opts = opts.InitOpts(bg_color=bg_color, width=width, height=height, animation_opts=opts.AnimationOpts(False))
    title_opts = opts.TitleOpts(
        title=title,
        pos_top="1%",
        title_textstyle_opts=opts.TextStyleOpts(color=up_color, font_size=20),
        subtitle_textstyle_opts=opts.TextStyleOpts(color=down_color, font_size=12),
    )

    label_show_opts = opts.LabelOpts(is_show=True)
    label_not_show_opts = opts.LabelOpts(is_show=False)
    legend_not_show_opts = opts.LegendOpts(is_show=False)
    red_item_style = opts.ItemStyleOpts(color=up_color)
    green_item_style = opts.ItemStyleOpts(color=down_color)
    k_style_opts = opts.ItemStyleOpts(
        color=up_color, color0=down_color, border_color=up_color, border_color0=down_color, opacity=0.8
    )

    legend_opts = opts.LegendOpts(
        is_show=True,
        pos_top="1%",
        pos_left="30%",
        item_width=14,
        item_height=8,
        textstyle_opts=opts.TextStyleOpts(font_size=12, color="#0e99e2"),
    )
    brush_opts = opts.BrushOpts(
        tool_box=["rect", "polygon", "keep", "clear"],
        x_axis_index="all",
        brush_link="all",
        out_of_brush={"colorAlpha": 0.1},
        brush_type="lineX",
    )

    axis_pointer_opts = opts.AxisPointerOpts(is_show=True, link=[{"xAxisIndex": "all"}])

    dz_inside = opts.DataZoomOpts(False, "inside", xaxis_index=[0, 1, 2], range_start=80, range_end=100)
    dz_slider = opts.DataZoomOpts(
        True, "slider", xaxis_index=[0, 1, 2], pos_top="96%", pos_bottom="0%", range_start=80, range_end=100
    )

    yaxis_opts = opts.AxisOpts(
        is_scale=True,
        min_="dataMin",
        max_="dataMax",
        splitline_opts=opts.SplitLineOpts(is_show=False),
        axislabel_opts=opts.LabelOpts(color="#c7c7c7", font_size=8, position="inside"),
    )

    grid0_xaxis_opts = opts.AxisOpts(
        type_="category",
        grid_index=0,
        axislabel_opts=label_not_show_opts,
        split_number=20,
        min_="dataMin",
        max_="dataMax",
        is_scale=True,
        boundary_gap=False,
        splitline_opts=opts.SplitLineOpts(is_show=False),
        axisline_opts=opts.AxisLineOpts(is_on_zero=False),
    )

    tool_tip_opts = opts.TooltipOpts(
        trigger="axis",
        axis_pointer_type="cross",
        background_color="rgba(245, 245, 245, 0.8)",
        border_width=1,
        border_color="#ccc",
        position=JsCode(
            """
                    function (pos, params, el, elRect, size) {
    					var obj = {top: 10};
    					obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
    					return obj;
    				}
                    """
        ),
        textstyle_opts=opts.TextStyleOpts(color="#000"),
    )

    # 数据预处理
    # ------------------------------------------------------------------------------------------------------------------
    dts = [x["dt"] for x in kline]
    # k_data = [[x['open'], x['close'], x['low'], x['high']] for x in kline]
    k_data = [
        opts.CandleStickItem(name=i, value=[x["open"], x["close"], x["low"], x["high"]]) for i, x in enumerate(kline)
    ]

    vol = []
    for i, row in enumerate(kline):
        item_style = red_item_style if row["close"] > row["open"] else green_item_style
        bar = opts.BarItem(name=i, value=row["vol"], itemstyle_opts=item_style, label_opts=label_not_show_opts)
        vol.append(bar)

    close = np.array([x["close"] for x in kline], dtype=np.double)
    diff, dea, macd = MACD(close)
    macd_bar = []
    for i, v in enumerate(macd.tolist()):
        item_style = red_item_style if v > 0 else green_item_style
        bar = opts.BarItem(name=i, value=round(v, 4), itemstyle_opts=item_style, label_opts=label_not_show_opts)
        macd_bar.append(bar)

    diff = diff.round(4)
    dea = dea.round(4)

    # K 线主图
    # ------------------------------------------------------------------------------------------------------------------
    chart_k = Kline()
    chart_k.add_xaxis(xaxis_data=dts)
    chart_k.add_yaxis(series_name="Kline", y_axis=k_data, itemstyle_opts=k_style_opts)

    chart_k.set_global_opts(
        legend_opts=legend_opts,
        datazoom_opts=[dz_inside, dz_slider],
        yaxis_opts=yaxis_opts,
        tooltip_opts=tool_tip_opts,
        axispointer_opts=axis_pointer_opts,
        brush_opts=brush_opts,
        title_opts=title_opts,
        xaxis_opts=grid0_xaxis_opts,
    )

    # 加入买卖点 - 多头操作 - 空头操作
    if bs:
        long_opens = {"i": [], "val": []}
        long_exits = {"i": [], "val": []}
        short_opens = {"i": [], "val": []}
        short_exits = {"i": [], "val": []}

        for op in bs:
            _dt = op["dt"]
            _price = round(op["price"], 4)
            _info = f"{op['op_desc']} - 价格{_price}"

            if op["op"] in [Operate.LO]:
                long_opens["i"].append(_dt)
                long_opens["val"].append([_price, _info])

            if op["op"] in [Operate.LE]:
                long_exits["i"].append(_dt)
                long_exits["val"].append([_price, _info])

            if op["op"] in [Operate.SO]:
                short_opens["i"].append(_dt)
                short_opens["val"].append([_price, _info])

            if op["op"] in [Operate.SE]:
                short_exits["i"].append(_dt)
                short_exits["val"].append([_price, _info])

        chart_lo = (
            Scatter()
            .add_xaxis(xaxis_data=long_opens["i"])
            .add_yaxis(
                series_name="多头操作",
                y_axis=long_opens["val"],
                symbol_size=25,
                symbol="diamond",
                label_opts=opts.LabelOpts(is_show=False),
                itemstyle_opts=opts.ItemStyleOpts(color="#ff461f"),
                tooltip_opts=opts.TooltipOpts(
                    textstyle_opts=opts.TextStyleOpts(font_size=12),
                    formatter=JsCode("function (params) {return params.value[2];}"),
                ),
            )
        )
        chart_le = (
            Scatter()
            .add_xaxis(xaxis_data=long_exits["i"])
            .add_yaxis(
                series_name="多头操作",
                y_axis=long_exits["val"],
                symbol_size=25,
                symbol="diamond",
                label_opts=opts.LabelOpts(is_show=False),
                itemstyle_opts=opts.ItemStyleOpts(color="#afdd22"),
                tooltip_opts=opts.TooltipOpts(
                    textstyle_opts=opts.TextStyleOpts(font_size=12),
                    formatter=JsCode("function (params) {return params.value[2];}"),
                ),
            )
        )
        chart_so = (
            Scatter()
            .add_xaxis(xaxis_data=short_opens["i"])
            .add_yaxis(
                series_name="空头订单",
                y_axis=short_opens["val"],
                symbol_size=25,
                symbol="triangle",
                label_opts=opts.LabelOpts(is_show=False),
                itemstyle_opts=opts.ItemStyleOpts(color="#ff461f"),
                tooltip_opts=opts.TooltipOpts(
                    textstyle_opts=opts.TextStyleOpts(font_size=12),
                    formatter=JsCode("function (params) {return params.value[2];}"),
                ),
            )
        )
        chart_se = (
            Scatter()
            .add_xaxis(xaxis_data=short_exits["i"])
            .add_yaxis(
                series_name="空头订单",
                y_axis=short_exits["val"],
                symbol_size=25,
                symbol="triangle",
                label_opts=opts.LabelOpts(is_show=False),
                itemstyle_opts=opts.ItemStyleOpts(color="#afdd22"),
                tooltip_opts=opts.TooltipOpts(
                    textstyle_opts=opts.TextStyleOpts(font_size=12),
                    formatter=JsCode("function (params) {return params.value[2];}"),
                ),
            )
        )

        chart_k = chart_k.overlap(chart_lo)
        chart_k = chart_k.overlap(chart_le)
        chart_k = chart_k.overlap(chart_so)
        chart_k = chart_k.overlap(chart_se)

    # 均线图
    # ------------------------------------------------------------------------------------------------------------------
    chart_ma = Line()
    chart_ma.add_xaxis(xaxis_data=dts)
    if not t_seq:
        t_seq = [5, 13, 21]

    ma_keys = dict()
    for t in t_seq:
        ma_keys[f"MA{t}"] = SMA(close, timeperiod=t)

    for i, (name, ma) in enumerate(ma_keys.items()):
        chart_ma.add_yaxis(
            series_name=name,
            y_axis=ma,
            is_smooth=True,
            symbol_size=0,
            label_opts=label_not_show_opts,
            linestyle_opts=opts.LineStyleOpts(opacity=0.8, width=1),
        )

    chart_ma.set_global_opts(xaxis_opts=grid0_xaxis_opts, legend_opts=legend_not_show_opts)
    chart_k = chart_k.overlap(chart_ma)

    # 缠论结果
    # ------------------------------------------------------------------------------------------------------------------
    if fx:
        fx_dts = [x["dt"] for x in fx]
        fx_val = [round(x["fx"], 2) for x in fx]
        chart_fx = Line()
        chart_fx.add_xaxis(fx_dts)
        chart_fx.add_yaxis(
            series_name="FX",
            y_axis=fx_val,
            symbol="circle",
            symbol_size=6,
            label_opts=label_show_opts,
            itemstyle_opts=opts.ItemStyleOpts(
                color="rgba(152, 147, 193, 1.0)",
            ),
        )

        chart_fx.set_global_opts(xaxis_opts=grid0_xaxis_opts, legend_opts=legend_not_show_opts)
        chart_k = chart_k.overlap(chart_fx)

    if bi:
        bi_dts = [x["dt"] for x in bi]
        bi_val = [round(x["bi"], 2) for x in bi]
        chart_bi = Line()
        chart_bi.add_xaxis(bi_dts)
        chart_bi.add_yaxis(
            series_name="BI",
            y_axis=bi_val,
            symbol="diamond",
            symbol_size=10,
            label_opts=label_show_opts,
            itemstyle_opts=opts.ItemStyleOpts(
                color="rgba(184, 117, 225, 1.0)",
            ),
            linestyle_opts=opts.LineStyleOpts(width=1.5),
        )

        chart_bi.set_global_opts(xaxis_opts=grid0_xaxis_opts, legend_opts=legend_not_show_opts)
        chart_k = chart_k.overlap(chart_bi)

    if xd:
        xd_dts = [x["dt"] for x in xd]
        xd_val = [x["xd"] for x in xd]
        chart_xd = Line()
        chart_xd.add_xaxis(xd_dts)
        chart_xd.add_yaxis(
            series_name="XD",
            y_axis=xd_val,
            symbol="triangle",
            symbol_size=10,
            itemstyle_opts=opts.ItemStyleOpts(
                color="rgba(37, 141, 54, 1.0)",
            ),
        )

        chart_xd.set_global_opts(xaxis_opts=grid0_xaxis_opts, legend_opts=legend_not_show_opts)
        chart_k = chart_k.overlap(chart_xd)

    # 成交量图
    # ------------------------------------------------------------------------------------------------------------------
    chart_vol = Bar()
    chart_vol.add_xaxis(dts)
    chart_vol.add_yaxis(series_name="Volume", y_axis=vol, bar_width="60%")
    chart_vol.set_global_opts(
        xaxis_opts=opts.AxisOpts(
            type_="category",
            grid_index=1,
            boundary_gap=False,
            axislabel_opts=opts.LabelOpts(is_show=True, font_size=8, color="#9b9da9"),
        ),
        yaxis_opts=yaxis_opts,
        legend_opts=legend_not_show_opts,
    )

    # MACD图
    # ------------------------------------------------------------------------------------------------------------------
    chart_macd = Bar()
    chart_macd.add_xaxis(dts)
    chart_macd.add_yaxis(series_name="MACD", y_axis=macd_bar, bar_width="60%")
    chart_macd.set_global_opts(
        xaxis_opts=opts.AxisOpts(
            type_="category",
            grid_index=2,
            axislabel_opts=opts.LabelOpts(is_show=False),
            splitline_opts=opts.SplitLineOpts(is_show=False),
        ),
        yaxis_opts=opts.AxisOpts(
            grid_index=2,
            split_number=4,
            axisline_opts=opts.AxisLineOpts(is_on_zero=False),
            axistick_opts=opts.AxisTickOpts(is_show=False),
            splitline_opts=opts.SplitLineOpts(is_show=False),
            axislabel_opts=opts.LabelOpts(is_show=True, color="#c7c7c7"),
        ),
        legend_opts=opts.LegendOpts(is_show=False),
    )

    line = Line()
    line.add_xaxis(dts)
    line.add_yaxis(
        series_name="DIFF",
        y_axis=diff.tolist(),
        label_opts=label_not_show_opts,
        is_symbol_show=False,
        linestyle_opts=opts.LineStyleOpts(opacity=0.8, width=1.0, color="#da6ee8"),
    )
    line.add_yaxis(
        series_name="DEA",
        y_axis=dea.tolist(),
        label_opts=label_not_show_opts,
        is_symbol_show=False,
        linestyle_opts=opts.LineStyleOpts(opacity=0.8, width=1.0, color="#39afe6"),
    )

    chart_macd = chart_macd.overlap(line)

    grid0_opts = opts.GridOpts(pos_left="0%", pos_right="1%", pos_top="12%", height="58%")
    grid1_opts = opts.GridOpts(pos_left="0%", pos_right="1%", pos_top="74%", height="8%")
    grid2_opts = opts.GridOpts(pos_left="0%", pos_right="1%", pos_top="86%", height="10%")

    grid_chart = Grid(init_opts)
    grid_chart.add(chart_k, grid_opts=grid0_opts)
    grid_chart.add(chart_vol, grid_opts=grid1_opts)
    grid_chart.add(chart_macd, grid_opts=grid2_opts)
    return grid_chart


def _prepare_kline_data(kline: List[dict], use_streamlit=False, width=1400, height=580) -> tuple:
    """准备K线数据

    :param kline: K线数据
    :return: (df_data, chart)
    """
    from loguru import logger
    import pandas as pd

    # 准备K线数据
    df_data = []
    for item in kline:
        # 处理时间格式
        if hasattr(item["dt"], "strftime"):
            time_str = item["dt"].strftime("%Y-%m-%d")
        else:
            time_str = str(item["dt"])

        df_data.append(
            {
                "time": time_str,
                "open": float(item["open"]),
                "high": float(item["high"]),
                "low": float(item["low"]),
                "close": float(item["close"]),
                "volume": float(item.get("vol", item.get("volume", 0))),
            }
        )

    # 创建主图表（延迟导入，避免在模块加载时引入 streamlit 等重型依赖）
    if use_streamlit:
        from lightweight_charts.widgets import StreamlitChart
        logger.info("使用 StreamlitChart")
        chart = StreamlitChart(width=width, height=height)
    else:
        from lightweight_charts import Chart
        logger.info("使用 Chart")
        chart = Chart()

    df = pd.DataFrame(df_data)
    chart.set(df)

    logger.info(f"成功创建基础K线图表，包含{len(df_data)}根K线")
    return df_data, chart


def _add_moving_averages(chart: "Chart", kline: List[dict], df_data: List[dict], t_seq: List[int]) -> None:
    """添加移动平均线

    :param chart: 图表对象
    :param kline: K线数据
    :param df_data: 格式化后的数据
    :param t_seq: 均线周期序列
    """
    from loguru import logger
    import pandas as pd

    if not t_seq:
        return

    try:
        close_prices = np.array([x["close"] for x in kline], dtype=np.double)
        # 均线颜色：橙色、蓝色、绿色、紫色、青色
        ma_colors = ["#FF9800", "#2196F3", "#4CAF50", "#9C27B0", "#00BCD4"]

        for i, period in enumerate(t_seq[:5]):  # 最多显示5条均线
            try:
                ma_values = SMA(close_prices, timeperiod=period)
                ma_data = []

                for j, item in enumerate(df_data):
                    if j >= period - 1 and j < len(ma_values) and not np.isnan(ma_values[j]):
                        ma_data.append({"time": item["time"], f"MA{period}": float(ma_values[j])})

                if ma_data:
                    ma_df = pd.DataFrame(ma_data).set_index("time")
                    color = ma_colors[i] if i < len(ma_colors) else "#999999"
                    ma_line = chart.create_line(f"MA{period}", color=color)
                    ma_line.set(ma_df)
                    logger.info(f"成功添加MA{period}均线（{color}），数据点数：{len(ma_data)}")
            except Exception as e:
                logger.warning(f"添加MA{period}均线失败: {e}")
                continue
    except Exception as e:
        logger.warning(f"添加移动平均线失败: {e}")


def _add_fractal_marks(chart: "Chart", fx: List[dict]) -> None:
    """添加分型标记

    :param chart: 图表对象
    :param fx: 分型数据
    """
    from loguru import logger
    import pandas as pd

    if not fx:
        return

    try:
        fx_data = []
        for item in fx:
            if hasattr(item["dt"], "strftime"):
                time_str = item["dt"].strftime("%Y-%m-%d")
            else:
                time_str = str(item["dt"])

            fx_data.append({"time": time_str, "分型": float(item["fx"])})

        if fx_data:
            fx_df = pd.DataFrame(fx_data).set_index("time")
            fx_line = chart.create_line("分型", color="#FF5722")  # 深橙红色
            fx_line.set(fx_df)
            logger.info(f"成功添加{len(fx_data)}个分型点（深橙红色）")
    except Exception as e:
        logger.warning(f"添加分型标记失败: {e}")


def _add_bi_lines(chart: "Chart", bi: List[dict]) -> None:
    """添加笔线

    :param chart: 图表对象
    :param bi: 笔数据
    """
    from loguru import logger
    import pandas as pd

    if not bi:
        return

    try:
        bi_data = []
        for item in bi:
            if hasattr(item["dt"], "strftime"):
                time_str = item["dt"].strftime("%Y-%m-%d")
            else:
                time_str = str(item["dt"])

            bi_data.append({"time": time_str, "笔": float(item["bi"])})

        if bi_data:
            bi_df = pd.DataFrame(bi_data).set_index("time")
            bi_line = chart.create_line("笔", color="#FFC107")  # 琥珀黄色
            bi_line.set(bi_df)
            logger.info(f"成功添加{len(bi_data)}笔（琥珀黄色）")
    except Exception as e:
        logger.warning(f"添加笔线失败: {e}")


def _add_xd_lines(chart: "Chart", xd: List[dict]) -> None:
    """添加线段

    :param chart: 图表对象
    :param xd: 线段数据
    """
    from loguru import logger
    import pandas as pd

    if not xd:
        return

    try:
        xd_data = []
        for item in xd:
            if hasattr(item["dt"], "strftime"):
                time_str = item["dt"].strftime("%Y-%m-%d")
            else:
                time_str = str(item["dt"])

            xd_data.append({"time": time_str, "线段": float(item["xd"])})

        if xd_data:
            xd_df = pd.DataFrame(xd_data).set_index("time")
            xd_line = chart.create_line("线段", color="#E91E63")  # 粉红色
            xd_line.set(xd_df)
            logger.info(f"成功添加{len(xd_data)}条线段（粉红色）")
    except Exception as e:
        logger.warning(f"添加线段失败: {e}")


def _add_macd_indicator(chart: "Chart", kline: List[dict], df_data: List[dict]) -> None:
    """添加MACD指标到子图表

    :param chart: 图表对象
    :param kline: K线数据
    :param df_data: 格式化后的数据
    """
    from loguru import logger
    import pandas as pd

    try:
        close_prices = np.array([x["close"] for x in kline], dtype=np.double)
        diff, dea, macd = MACD(close_prices)

        # 尝试创建子图表用于MACD显示
        try:
            # 重新设置主图高度，为子图腾出空间
            chart.resize(1, 0.7)  # 主图占70%高度

            # 隐藏主图的时间轴，避免重复显示
            chart.time_scale(visible=False)

            # 创建MACD子图表，占30%高度并同步时间轴
            macd_chart = chart.create_subchart(width=1, height=0.3, sync=True)

            # 确保子图显示时间轴，并设置时间轴格式保持一致
            macd_chart.time_scale(visible=True, time_visible=True, seconds_visible=False)

            logger.info("成功创建MACD子图表并设置时间轴同步")
        except Exception as subchart_e:
            # 如果不支持子图表，直接返回
            logger.warning(f"子图表创建失败，跳过MACD指标: {subchart_e}")
            return

        # 确保所有数组长度一致
        data_length = min(len(df_data), len(diff), len(dea), len(macd))

        # 重要：对NaN值填充为0，确保数据长度一致，保证时间轴对齐
        diff_line_data = []
        dea_line_data = []
        histogram_data = []

        for j in range(data_length):
            time_value = df_data[j]["time"]

            # 对NaN值填充为0，而不是跳过，确保数据长度一致
            diff_val = 0.0 if np.isnan(diff[j]) else float(diff[j])
            dea_val = 0.0 if np.isnan(dea[j]) else float(dea[j])
            macd_val = 0.0 if np.isnan(macd[j]) else float(macd[j])

            diff_line_data.append({"time": time_value, "value": diff_val})

            dea_line_data.append({"time": time_value, "value": dea_val})

            histogram_data.append(
                {"time": time_value, "value": macd_val, "color": "#26a69a" if macd_val >= 0 else "#ef5350"}
            )

        logger.info(
            f"MACD数据准备完成：总数据长度{data_length}，DIFF({len(diff_line_data)})，DEA({len(dea_line_data)})，柱状图({len(histogram_data)})"
        )

        # 添加DIFF线（MACD快线）
        if diff_line_data:
            diff_df = pd.DataFrame(diff_line_data)
            diff_line = macd_chart.create_line(color="#1976D2", width=2)  # 深蓝色
            diff_line.set(diff_df)
            logger.info(f"成功添加DIFF线（深蓝色），数据点数：{len(diff_line_data)}")

        # 添加DEA线（MACD慢线/信号线）
        if dea_line_data:
            dea_df = pd.DataFrame(dea_line_data)
            dea_line = macd_chart.create_line(color="#FF5722", width=2)  # 橙红色
            dea_line.set(dea_df)
            logger.info(f"成功添加DEA线（橙红色），数据点数：{len(dea_line_data)}")

        # 添加MACD柱状图
        if histogram_data:
            histogram_df = pd.DataFrame(histogram_data)
            macd_histogram = macd_chart.create_histogram()
            macd_histogram.set(histogram_df)
            logger.info(f"成功添加MACD柱状图，数据点数：{len(histogram_data)}")

        # 设置子图表样式和联动
        macd_chart.legend(visible=True)

        # 添加一些样式设置以确保更好的视觉效果
        try:
            # 设置MACD子图的网格线
            macd_chart.grid(vert_enabled=True, horz_enabled=True)

            # 确保子图的十字光标与主图同步
            macd_chart.crosshair(
                mode="normal", vert_color="#758494", vert_style="dotted", horz_color="#758494", horz_style="dotted"
            )
        except Exception as style_e:
            logger.debug(f"设置MACD子图样式时出现警告: {style_e}")

        logger.info("MACD子图与主图时间轴联动设置完成")

    except Exception as e:
        logger.warning(f"添加MACD指标失败: {e}")


def _add_trade_signals(chart: "Chart", bs: List[dict]) -> None:
    """添加买卖点标记

    :param chart: 图表对象
    :param bs: 买卖点数据
    """
    from loguru import logger
    from datetime import datetime

    if not bs:
        return

    try:
        for signal in bs:
            # 处理时间格式
            if hasattr(signal["dt"], "strftime"):
                marker_time = signal["dt"]
            else:
                # 尝试转换为datetime对象
                try:
                    marker_time = datetime.strptime(str(signal["dt"]), "%Y-%m-%d")
                except:
                    marker_time = None

            if marker_time is None:
                continue

            # 根据操作类型设置不同的标记
            if signal["op"] in [Operate.LO]:  # 买入开仓
                chart.marker(
                    time=marker_time,
                    position="below",
                    shape="circle",
                    color="#4CAF50",
                    text=signal.get("op_desc", "买入"),
                )
            elif signal["op"] in [Operate.LE]:  # 卖出平仓
                chart.marker(
                    time=marker_time,
                    position="above",
                    shape="circle",
                    color="#F44336",
                    text=signal.get("op_desc", "卖出"),
                )
            elif signal["op"] in [Operate.SO]:  # 卖出开仓
                chart.marker(
                    time=marker_time,
                    position="above",
                    shape="arrow_down",
                    color="#FF9800",
                    text=signal.get("op_desc", "做空"),
                )
            elif signal["op"] in [Operate.SE]:  # 买入平仓
                chart.marker(
                    time=marker_time,
                    position="below",
                    shape="arrow_up",
                    color="#2196F3",
                    text=signal.get("op_desc", "平空"),
                )

        logger.info(f"成功添加{len(bs)}个买卖点标记")
    except Exception as e:
        logger.exception(f"添加买卖点标记失败: {e}")


def _setup_chart_style(chart: "Chart", title: str) -> None:
    """设置图表样式

    :param chart: 图表对象
    :param title: 图表标题
    """
    from loguru import logger

    try:
        # 设置图表样式
        chart.legend(visible=True)
        chart.watermark(title)

        # 可以添加更多样式设置
        # chart.layout(background_color='#FFFFFF', text_color='#000000')
        # chart.grid(vert_enabled=True, horz_enabled=True)

        logger.info(f"成功设置图表样式和标题: {title}")
    except Exception as e:
        logger.warning(f"设置图表样式失败: {e}")


def trading_view_kline(
    kline: List[dict],
    fx: Optional[List[dict]] = None,
    bi: Optional[List[dict]] = None,
    xd: Optional[List[dict]] = None,
    bs: Optional[List[dict]] = None,
    title: str = "缠中说禅K线分析",
    t_seq: Optional[List[int]] = None,
    **kwargs,
) -> Optional["Chart"]:
    """使用 lightweight_charts 绘制缠中说禅K线分析结果

    注意：本函数提供基础的lightweight_charts集成。
    如需完整功能和更好的视觉效果，建议使用 kline_pro 函数。

    :param kline: K线数据
    :param fx: 分型识别结果
    :param bi: 笔识别结果
    :param xd: 线段识别结果
    :param bs: 买卖点
    :param title: 图表标题
    :param t_seq: 均线系统
    :return: lightweight_charts Chart对象 或 None
    """
    from loguru import logger
    import pandas as pd

    # 设置默认值
    fx = fx or []
    bi = bi or []
    xd = xd or []
    bs = bs or []
    t_seq = t_seq or [5, 13, 21]

    use_streamlit = kwargs.get("use_streamlit", False)
    width = kwargs.get("width", 1400)
    height = kwargs.get("height", 580)

    # 准备K线数据
    df_data, chart = _prepare_kline_data(kline, use_streamlit, width, height)

    # 添加移动平均线
    _add_moving_averages(chart, kline, df_data, t_seq)

    # 添加分型标记
    _add_fractal_marks(chart, fx)

    # 添加笔线
    _add_bi_lines(chart, bi)

    # 添加线段
    _add_xd_lines(chart, xd)

    # 添加MACD指标
    _add_macd_indicator(chart, kline, df_data)

    # 添加买卖点标记
    _add_trade_signals(chart, bs)

    # 设置图表样式
    _setup_chart_style(chart, title)

    logger.info(f"创建 lightweight_charts 图表成功: {title}")
    logger.info(f"包含: K线({len(kline)}), 均线({len(t_seq)}), 分型({len(fx)}), 笔({len(bi)}), 线段({len(xd)}), MACD")

    return chart
