"""运行时桩：欺骗 mediapipe.tasks.python.vision 让其认为 matplotlib 已可用
背景：mediapipe.tasks.python.vision 顶层导入时加载 drawing_styles.py，
后者 import matplotlib —— 但我们用 Tkinter Canvas 画骨骼，不需要 matplotlib 真绘制。
在 PyInstaller 打包后 matplotlib 已被排除，否则会运行时报错。
"""
import sys
import types


def _to_rgba(c, alpha=None):
    if alpha is None:
        alpha = 1.0
    if isinstance(c, (int, float)):
        return (float(c), float(c), float(c), alpha)
    if isinstance(c, str):
        try:
            h = c.lstrip('#')
            if len(h) == 6:
                r, g, b = int(h[0:2], 16) / 255.0, int(h[2:4], 16) / 255.0, int(h[4:6], 16) / 255.0
                return (r, g, b, alpha)
        except Exception:
            pass
    return (0.5, 0.5, 0.5, alpha)


def _to_rgb(c):
    return _to_rgba(c)[:3]


def _hsv_to_rgb(h, s, v):
    if s == 0.0:
        return (v, v, v)
    h = (float(h) % 1.0) * 6.0
    i = int(h)
    f = h - i
    p = v * (1.0 - s)
    q = v * (1.0 - s * f)
    t = v * (1.0 - s * (1.0 - f))
    if i == 0: return (v, t, p)
    if i == 1: return (q, v, p)
    if i == 2: return (p, v, t)
    if i == 3: return (p, q, v)
    if i == 4: return (t, p, v)
    return (v, p, q)


def _make_cmap(name=None):
    """假色卡 —— 任何索引都返回中性灰，避免视觉残留但不会崩。"""
    def cmap(x, alpha=None):
        return _to_rgba(x, alpha)

    cmap.N = 256
    cmap.name = name or 'viridis'
    cmap.colors = lambda: [(0.5, 0.5, 0.5)] * cmap.N
    cmap.resampled = lambda n: cmap
    cmap.reversed = lambda n: cmap
    return cmap


class _ScalarMappable:
    def __init__(self, *args, cmap=None, **kwargs):
        self.cmap = cmap if cmap is not None else _make_cmap()

    def to_rgba(self, x, alpha=None, bytes=False):
        try:
            if hasattr(x, '__iter__') and not isinstance(x, str):
                result = [_to_rgba(v, alpha) for v in x]
                if bytes:
                    return [tuple(int(v * 255) for v in t) for t in result]
                return result
        except Exception:
            pass
        rgba = _to_rgba(x, alpha)
        if bytes:
            return tuple(int(v * 255) for v in rgba)
        return rgba

    def get_cmap(self): return self.cmap
    def set_array(self, *a, **k): pass
    def set_cmap(self, *a, **k): pass


# ============================================================
#  关键修复：matplotlib 子模块不能直接继承 ModuleType，否则 __getattr__ 会失效
#  解决：把常用属性逐个写入模块 __dict__，并用 getattr 钩子兜底
# ============================================================

def _make_module_with_attrs(name, attrs):
    m = types.ModuleType(name)
    for k, v in attrs.items():
        setattr(m, k, v)
    sys.modules[name] = m
    return m


class _LazyColormapModule(types.ModuleType):
    """未明确定义的属性 → 默认色卡（模拟 matplotlib ColormapRegistry）"""
    def __init__(self, name, attrs=None):
        super().__init__(name)
        if attrs:
            for k, v in attrs.items():
                setattr(self, k, v)

    def __getattr__(self, name):
        if name.startswith('_'):
            raise AttributeError(name)
        cmap = _make_cmap(name)
        setattr(self, name, cmap)  # 缓存
        return cmap


class _FakeFigure:
    def __init__(self, *args, **kwargs): pass
    def subplots_adjust(self, *a, **k): pass
    def add_subplot(self, *a, **k): return _FakeAxes()
    def savefig(self, *a, **k): pass
    def clear(self, *a, **k): pass
    def set_size_inches(self, *a, **k): pass
    def tight_layout(self, *a, **k): pass
    def suptitle(self, *a, **k): pass
    def colorbar(self, *a, **k): pass
    def get_axes(self): return []


class _FakeAxes:
    def __init__(self, *a, **k): pass
    def plot(self, *a, **k): return []
    def scatter(self, *a, **k): return []
    def add_patch(self, *a, **k): return None
    def add_collection(self, *a, **k): return None
    def add_line(self, *a, **k): return None
    def set_xlim(self, *a, **k): pass
    def set_ylim(self, *a, **k): pass
    def set_aspect(self, *a, **k): pass
    def axis(self, *a, **k): pass
    def imshow(self, *a, **k): return None
    def set_title(self, *a, **k): pass
    def legend(self, *a, **k): pass
    def text(self, *a, **k): pass


def install_matplotlib_stub():
    # 幂等：已安装则跳过
    if 'matplotlib.cm' in sys.modules and getattr(sys.modules['matplotlib.cm'], '_stub_marker', False):
        return

    # matplotlib 顶层包
    mpl = types.ModuleType('matplotlib')
    mpl.__path__ = []
    mpl.__file__ = __file__
    mpl.__version__ = '0.0.0-stub'
    sys.modules['matplotlib'] = mpl

    # matplotlib.colors
    colors_attrs = {
        'to_rgb': _to_rgb,
        'to_rgba': _to_rgba,
        'hsv_to_rgb': _hsv_to_rgb,
        'to_hex': lambda c: '#808080',
        'is_color_like': lambda c: True,
        'CSS4_COLORS': {},
        'TABLEAU_COLORS': {},
        'XKCD_COLORS': {},
        '_stub_marker': True,
    }
    colors = _LazyColormapModule('matplotlib.colors', colors_attrs)
    setattr(colors, '_stub_marker', True)
    sys.modules['matplotlib.colors'] = colors
    mpl.colors = colors

    # matplotlib.cm —— 这里是最关键的，drawing_styles 要 plt.cm.hsv(...) 取色卡
    cm_attrs = {
        'get_cmap': _make_cmap,
        'ScalarMappable': _ScalarMappable,
        '_stub_marker': True,
    }
    cm = _LazyColormapModule('matplotlib.cm', cm_attrs)
    setattr(cm, '_stub_marker', True)
    sys.modules['matplotlib.cm'] = cm
    mpl.cm = cm

    # matplotlib.pyplot —— 模拟 figure/subplots/show 等
    pyplot_attrs = {
        'figure': lambda *a, **k: _FakeFigure(),
        'subplots': lambda *a, **k: (_FakeFigure(), _FakeAxes()),
        'subplot': lambda *a, **k: _FakeAxes(),
        'close': lambda *a, **k: None,
        'show': lambda *a, **k: None,
        'clf': lambda *a, **k: None,
        'cla': lambda *a, **k: None,
        'draw': lambda *a, **k: None,
        'pause': lambda *a, **k: None,
        'ion': lambda *a, **k: None,
        'ioff': lambda *a, **k: None,
        'isinteractive': lambda *a, **k: False,
        'gcf': lambda: _FakeFigure(),
        'gca': lambda: _FakeAxes(),
        'imsave': lambda *a, **k: None,
        'imread': lambda *a, **k: None,
        'cm': cm,  # plt.cm 等价于 matplotlib.cm
    }
    pyplot = _LazyColormapModule('matplotlib.pyplot', pyplot_attrs)
    sys.modules['matplotlib.pyplot'] = pyplot
    mpl.pyplot = pyplot

    # matplotlib.figure（部分模块会引用 Figure 类）
    figure_mod = types.ModuleType('matplotlib.figure')
    figure_mod.Figure = _FakeFigure
    sys.modules['matplotlib.figure'] = figure_mod
    mpl.figure = figure_mod

    # matplotlib.backend_bases（兜底，避免 drawing_utils 等引用）
    bb_mod = types.ModuleType('matplotlib.backend_bases')
    class _FakeRendererBase:
        def __init__(self, *a, **k): pass
    bb_mod.RendererBase = _FakeRendererBase
    bb_mod.FigureCanvasBase = type('FigureCanvasBase', (), {})
    sys.modules['matplotlib.backend_bases'] = bb_mod
    mpl.backend_bases = bb_mod

    # 标记主 matplotlib 安装好了
    setattr(mpl, '_stub_marker', True)


# ============================================================
#  自动启动逻辑：
#  - 已被 stub 接管 → 直接返回
#  - 真实 matplotlib 已加载 → 跳过 stub（开发环境用真实 matplotlib）
#  - 否则 → 安装 stub
# ============================================================

_already_installed = (
    'matplotlib' in sys.modules
    and getattr(sys.modules.get('matplotlib'), '_stub_marker', False)
)

if not _already_installed:
    try:
        import matplotlib  # noqa: F401
        # 真实 matplotlib 已加载 —— 不动它
    except ImportError:
        # 没有 matplotlib —— 安装桩
        install_matplotlib_stub()
