import json
from imgui_bundle import imgui
from .file_dialogs import save_file
from bcad.binterpreter.rqq import requests, RQ_CANCEL
from bcad.binterpreter.singleton import Singleton

class ViewTools:
    icon_loader = None
    display_shaded = True
    display_edges = False
    projection = 'perspective'

    @classmethod
    def render_view_menu(cls, rqq):
        if imgui.begin_menu("Orientation", True):
            for label, v in [("Top","top"),("Bottom","bottom"),("Left","left"),("Right","right"),("Front","front"),("Rear","rear")]:
                clicked, _ = imgui.menu_item(label, "", False, True)
                if clicked:
                    rqq.rq_set_view(v)
            imgui.separator()
            for i in range(1, 9):
                clicked, _ = imgui.menu_item(f"Iso{i}", "", False, True)
                if clicked:
                    rqq.rq_set_view(f"iso{i}")
            imgui.end_menu()
        if imgui.begin_menu("Display", True):
            _, cls.display_shaded = imgui.menu_item("Shaded", "", cls.display_shaded, True)
            clicked_shaded = imgui.is_item_clicked()
            _, cls.display_edges = imgui.menu_item("Wireframe", "", cls.display_edges, True)
            clicked_edges = imgui.is_item_clicked()
            if clicked_shaded or clicked_edges:
                if not cls.display_shaded and not cls.display_edges:
                    if clicked_shaded:
                        cls.display_edges = True
                    else:
                        cls.display_shaded = True
                rqq.rq_set_display_state(cls.display_shaded, cls.display_edges)
            imgui.end_menu()
        if imgui.begin_menu("Projection", True):
            for mode in ('orthographic', 'perspective'):
                checked = cls.projection == mode
                clicked, cls.projection = imgui.menu_item(mode.capitalize(), "", checked, True)
                if clicked:
                    rqq.rq_set_projection(mode)
            imgui.end_menu()
        imgui.separator()
        if imgui.menu_item("Reset View", "", False, True)[0]:
            rqq.rq_view_action('reset_view')
        if imgui.menu_item("Fit All", "", False, True)[0]:
            rqq.rq_view_action('fit_all')
        imgui.separator()
        if imgui.begin_menu("Triedron", True):
            if imgui.menu_item("Show", "", False, True)[0]:
                rqq.rq_view_action('triedron_show')
            if imgui.menu_item("Hide", "", False, True)[0]:
                rqq.rq_view_action('triedron_hide')
            imgui.end_menu()

    @classmethod
    def _render_reload_toolbar(cls, rqq, send_urgent):
        if hasattr(Singleton, 'sh_progress_current'):
            current = Singleton.sh_progress_current.value
            total   = Singleton.sh_progress_total.value
            label   = bytes(Singleton.sh_progress_label.value).rstrip(b'\x00').decode('utf-8', errors='replace')
        else:
            current = 0
            total = 1
            label = 'Executing'
        if total < 1:
            total = 1

        imgui.set_cursor_pos(imgui.ImVec2(4, 4))
        if imgui.button("Cancel", imgui.ImVec2(60, 0)):
            if send_urgent:
                send_urgent(json.dumps({'rq': requests[RQ_CANCEL], 'args': []}))
            rqq.rq_cancel()
        imgui.same_line(spacing=4)

        avail = imgui.get_content_region_avail()
        bar_w = max(1, int(avail.x - 4))

        text = f"{label} ({current}/{total})"
        tw = imgui.calc_text_size(text).x
        bar_pos = imgui.get_cursor_pos()
        imgui.progress_bar(current / total, imgui.ImVec2(bar_w, 0), "")
        imgui.set_cursor_pos(imgui.ImVec2(
            bar_pos.x + bar_w - tw - 4,
            bar_pos.y + 1
        ))
        imgui.text(text)

    @classmethod
    def render_toolbar_content(cls, rqq, reloading=False, send_urgent=None):

        if reloading:
            cls._render_reload_toolbar(rqq, send_urgent)
            return

        def _btn(icon_name, fallback_label, tooltip=None):
            if cls.icon_loader is not None:
                clicked = cls.icon_loader.button(icon_name, fallback_label, icon_size=24)
            else:
                clicked = imgui.button(fallback_label, imgui.ImVec2(30, 30))

            imgui.push_style_var(imgui.StyleVar_.window_padding, imgui.ImVec2(8,8))
            if tooltip and imgui.begin_item_tooltip():
                imgui.text(tooltip)
                imgui.end_tooltip()
            imgui.pop_style_var(1)

            return clicked

        def _push_btn_colors(checked=None):
            imgui.push_style_color(imgui.Col_.button_active, imgui.get_color_u32(imgui.Col_.button_hovered))
            imgui.push_style_color(imgui.Col_.button_hovered, imgui.get_color_u32(imgui.Col_.button))
            if checked is not None and checked:
                imgui.push_style_color(imgui.Col_.button, imgui.get_color_u32(imgui.Col_.button_hovered))
            else:
                imgui.push_style_color(imgui.Col_.button, imgui.ImVec4(1.0, 1.0, 1.0, 0.0))

        def _pop_btn_colors():
            imgui.pop_style_color(3)

        for icon, view, fallback, tip in [
            ("view-top", "top", "Tp", "Top view"),
            ("view-bottom", "bottom", "Bt", "Bottom view"),
            ("view-left", "left", "L", "Left view"),
            ("view-right", "right", "R", "Right view"),
            ("view-front", "front", "F", "Front view"),
            ("view-rear", "rear", "Rr", "Rear view"),
        ]:
            _push_btn_colors()
            if _btn(icon, fallback, tip):
                rqq.rq_set_view(view)
            _pop_btn_colors()
            imgui.same_line(spacing=0)

        _push_btn_colors()
        if _btn("view-iso", "Iso", "Isometric"):
            rqq.rq_set_view('iso1')
        _pop_btn_colors()

        imgui.same_line(spacing=16)

        _push_btn_colors()
        if _btn("action-fit", "Fit", "Fit All"):
            rqq.rq_view_action('fit_all')
        _pop_btn_colors()
        imgui.same_line(spacing=0)

        _push_btn_colors()
        if _btn("action-reset", "Rst", "Reset View"):
            rqq.rq_view_action('reset_view')
        _pop_btn_colors()

        imgui.same_line(spacing=16)

        _push_btn_colors(cls.display_shaded)
        if _btn("display-shaded", "Shd", "Shaded"):
            if cls.display_shaded and not cls.display_edges:
                cls.display_shaded = False
                cls.display_edges = True
            else:
                cls.display_shaded = not cls.display_shaded
            rqq.rq_set_display_state(cls.display_shaded, cls.display_edges)
        _pop_btn_colors()
        imgui.same_line(spacing=0)

        _push_btn_colors(cls.display_edges)
        if _btn("display-wireframe", "Wir", "Wireframe"):
            if cls.display_edges and not cls.display_shaded:
                cls.display_edges = False
                cls.display_shaded = True
            else:
                cls.display_edges = not cls.display_edges
            rqq.rq_set_display_state(cls.display_shaded, cls.display_edges)
        _pop_btn_colors()
        imgui.same_line(spacing=0)

        imgui.same_line(spacing=16)
        for mode, icon, fb, tip in [
            ("orthographic", "projection-orthographic", "Orth", "Orthographic"),
            ("perspective", "projection-perspective", "Pers", "Perspective"),
        ]:
            checked = cls.projection == mode
            _push_btn_colors(checked)
            if _btn(icon, fb, tip):
                cls.projection = mode
                rqq.rq_set_projection(mode)
            _pop_btn_colors()
            imgui.same_line(spacing=0)

        imgui.same_line(spacing=16)
        _push_btn_colors()
        if _btn("action-export", "Ex", "Export file"):
            imgui.open_popup("export_popup")
        _pop_btn_colors()

        imgui.push_style_var(imgui.StyleVar_.window_padding, imgui.ImVec2(8,8))
        if imgui.begin_popup("export_popup"):
            if imgui.menu_item("Export Image (PNG)...", "", False, True)[0]:
                cls.export_image(rqq)
            imgui.separator()
            if imgui.menu_item("Export STEP...", "", False, True)[0]:
                path = save_file("Export STEP", filters=["STEP files", "*.step"])
                if path:
                    rqq.rq_export_geometry(path, 'step')
            if imgui.menu_item("Export STL...", "", False, True)[0]:
                path = save_file("Export STL", filters=["STL files", "*.stl"])
                if path:
                    rqq.rq_export_geometry(path, 'stl')
            if imgui.menu_item("Export DXF...", "", False, True)[0]:
                path = save_file("Export DXF", filters=["DXF files", "*.dxf"])
                if path:
                    rqq.rq_export_geometry(path, 'dxf')
            imgui.end_popup()
        imgui.pop_style_var(1)
        imgui.same_line(spacing=16)


    @classmethod
    def export_image(cls, rqq):
        result = save_file("Export Image",
                           filters=["PNG files", "*.png", "All files", "*"])
        if result:
            rqq.rq_view_action('export_image', result)
