from types import SimpleNamespace

import moderngl as mgl
import numpy as np

from topovec.mgl.axes import AxesRender


def test_axes_render_restores_framebuffer_masks():
    class DummyFramebuffer:
        def __init__(self):
            self.color_mask = (False, True, False, True)
            self.depth_mask = False
            self.clear_calls = 0
            self.use_calls = 0

        def clear(self):
            self.clear_calls += 1

        def use(self):
            self.use_calls += 1

    class DummyContext:
        def __init__(self):
            self.fbo = DummyFramebuffer()
            self.enabled = []

        def enable_only(self, flags):
            self.enabled.append(flags)

    class DummyVao:
        def __init__(self):
            self.calls = []

        def render(self, **kwargs):
            self.calls.append(kwargs)

    axes = AxesRender.__new__(AxesRender)
    axes._ctx = DummyContext()
    axes._vao = DummyVao()
    axes.u_view = SimpleNamespace(value=None)
    axes.u_projection = SimpleNamespace(value=None)
    axes.u_ratio = SimpleNamespace(value=None)
    axes.u_length = SimpleNamespace(value=None)
    axes.u_location = SimpleNamespace(value=None)
    axes.ratio = 0.2
    axes.length = 0.1
    axes.location_x = -0.8
    axes.location_y = -0.8

    original_color_mask = axes._ctx.fbo.color_mask
    original_depth_mask = axes._ctx.fbo.depth_mask

    axes.render(modelview=np.eye(4), projection=np.eye(4))

    assert axes._ctx.fbo.clear_calls == 1
    assert axes._ctx.fbo.use_calls == 2
    assert axes._ctx.enabled == [mgl.DEPTH_TEST]
    assert axes._ctx.fbo.color_mask == original_color_mask
    assert axes._ctx.fbo.depth_mask == original_depth_mask
    assert axes.u_ratio.value == axes.ratio
    assert axes.u_length.value == axes.length
    assert axes.u_location.value == (axes.location_x, axes.location_y)
    assert len(axes._vao.calls) == 1


def test_axes_render_rebuild_releases_previous_geometry(monkeypatch):
    class DummyMesh:
        created = []

        def __init__(self, mglctx=None, count=None):
            self.mglctx = mglctx
            self.count = count
            self.pos = SimpleNamespace(vbo=object())
            self.normal = SimpleNamespace(vbo=object())
            self.idx = SimpleNamespace(ibo=object())
            self.release_calls = 0
            type(self).created.append(self)

        def release(self):
            self.release_calls += 1

    class DummyVao:
        def __init__(self):
            self.release_calls = 0

        def release(self):
            self.release_calls += 1

    class DummyContext:
        def __init__(self):
            self.created_vaos = []

        def vertex_array(self, _prog, _bindings, _ibo=None):
            vao = DummyVao()
            self.created_vaos.append(vao)
            return vao

    monkeypatch.setattr("topovec.mgl.axes.ArrowMesh", DummyMesh)

    axes = AxesRender.__new__(AxesRender)
    axes._ctx = DummyContext()
    axes._prog = object()
    axes._mesh_count = 10
    axes._directionBuffer = SimpleNamespace(vbo=object())
    axes._originBuffer = SimpleNamespace(vbo=object())
    axes._colorBuffer = SimpleNamespace(vbo=object())

    axes.init_vao()
    first_mesh = axes.mesh
    first_vao = axes._vao

    axes.init_vao()

    assert first_mesh.release_calls == 1
    assert first_vao.release_calls == 1
    assert axes.mesh is not first_mesh
    assert axes._vao is not first_vao
