bl_info = {
    "name": "Edge Length Custom Overlay",
    "author": "ChatGPT, LOL",
    "version": (1, 0),
    "blender": (4, 0, 0),
    "location": "View3D",
    "description": "Displays edge lengths with custom overlay",
    "category": "3D View",
}

import bpy
import bmesh
import blf
from bpy.props import IntProperty, FloatProperty, EnumProperty, FloatVectorProperty, BoolProperty
from bpy_extras.view3d_utils import location_3d_to_region_2d

draw_handler = None


# ✅ Unit tables (suffix removed from output)
METRIC_UNITS = {
    'KILOMETERS': 0.001,
    'METERS': 1.0,
    'CENTIMETERS': 100.0,
    'MILLIMETERS': 1000.0,
    'MICROMETERS': 1_000_000.0,
}

IMPERIAL_UNITS = {
    'MILES': 0.000621371,
    'FEET': 3.28084,
    'INCHES': 39.3701,
    'THOU': 39370.1,
}


def format_length(value, precision, context):
    us = context.scene.unit_settings

    scaled = value * us.scale_length

    if us.system == 'METRIC':
        factor = METRIC_UNITS.get(us.length_unit, 1.0)
    elif us.system == 'IMPERIAL':
        factor = IMPERIAL_UNITS.get(us.length_unit, 3.28084)
    else:
        factor = 1.0

    final_value = scaled * factor
    rounded = round(final_value, precision)

    if rounded.is_integer():
        return str(int(rounded))
    else:
        return f"{rounded:.{precision}f}".rstrip('0').rstrip('.')


def draw_text(font_id, text, x, y, scene):
    color = scene.edge_overlay_color
    shadow = scene.edge_overlay_shadow
    outline = scene.edge_overlay_outline

    # ✅ Shadow (simple offset)
    if shadow:
        blf.color(font_id, 0, 0, 0, 0.5)
        blf.position(font_id, x + 1, y - 1, 0)
        blf.draw(font_id, text)

    # ✅ Outline (draw 4 directions)
    if outline:
        blf.color(font_id, 0, 0, 0, 1)
        offsets = [(-1,0),(1,0),(0,-1),(0,1)]
        for ox, oy in offsets:
            blf.position(font_id, x + ox, y + oy, 0)
            blf.draw(font_id, text)

    # ✅ Main text
    blf.color(font_id, *color)
    blf.position(font_id, x, y, 0)
    blf.draw(font_id, text)


def draw_callback():
    context = bpy.context
    scene = context.scene

    obj = context.object
    if not obj or obj.type != 'MESH':
        return

    if context.mode != 'EDIT_MESH':
        return

    region = context.region
    rv3d = context.region_data

    if not region or not rv3d:
        return

    bm = bmesh.from_edit_mesh(obj.data)

    font_size = scene.edge_overlay_font_size
    threshold = scene.edge_overlay_threshold
    precision = scene.edge_overlay_precision
    mode = scene.edge_overlay_mode

    edges = []

    if mode == 'NONE':
        return
    elif mode == 'ACTIVE':
        edge = bm.select_history.active
        if isinstance(edge, bmesh.types.BMEdge):
            edges = [edge]
    elif mode == 'SELECTED':
        edges = [e for e in bm.edges if e.select]
    elif mode == 'ALL':
        edges = bm.edges

    font_id = 0
    blf.size(font_id, font_size)

    for edge in edges:
        v1, v2 = edge.verts

        co1 = obj.matrix_world @ v1.co
        co2 = obj.matrix_world @ v2.co

        length = (co2 - co1).length

        if (length * scene.unit_settings.scale_length) < threshold:
            continue

        center = (co1 + co2) / 2

        screen_pos = location_3d_to_region_2d(region, rv3d, center)
        if screen_pos is None:
            continue

        text = format_length(length, precision, context)

        draw_text(font_id, text, screen_pos.x, screen_pos.y, scene)


# ✅ Panel
class VIEW3D_PT_edge_overlay(bpy.types.Panel):
    bl_label = "Custom Overlays"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "View"

    def draw(self, context):
        layout = self.layout
        scene = context.scene

        col = layout.column()
        col.label(text="Edge length")

        col.prop(scene, "edge_overlay_mode")
        col.prop(scene, "edge_overlay_font_size")
        col.prop(scene, "edge_overlay_precision")
        col.prop(scene, "edge_overlay_threshold")
        col.prop(scene, "edge_overlay_color")
        col.prop(scene, "edge_overlay_shadow")
        col.prop(scene, "edge_overlay_outline")


def register():
    global draw_handler

    bpy.types.Scene.edge_overlay_font_size = IntProperty(
        name="Text Size",
        default=20,
        min=8,
        max=100
    )

    bpy.types.Scene.edge_overlay_precision = IntProperty(
        name="Rounding",
        default=4,
        min=0,
        max=10
    )

    bpy.types.Scene.edge_overlay_threshold = FloatProperty(
        name="Length Threshold",
        default=0.0,
        min=0.0
    )

    bpy.types.Scene.edge_overlay_mode = EnumProperty(
        name="Edges",
        items=[
            ('NONE', "None", ""),
            ('ACTIVE', "Active", ""),
            ('SELECTED', "Selected", ""),
            ('ALL', "All", ""),
        ],
        default='ACTIVE'
    )

    bpy.types.Scene.edge_overlay_color = FloatVectorProperty(
        name="Text Color",
        subtype='COLOR',
        size=4,
        default=(1.0, 1.0, 1.0, 1.0),
        min=0.0,
        max=1.0
    )

    bpy.types.Scene.edge_overlay_shadow = BoolProperty(
        name="Shadow",
        default=False
    )

    bpy.types.Scene.edge_overlay_outline = BoolProperty(
        name="Outline",
        default=False
    )

    bpy.utils.register_class(VIEW3D_PT_edge_overlay)

    draw_handler = bpy.types.SpaceView3D.draw_handler_add(
        draw_callback,
        (),
        'WINDOW',
        'POST_PIXEL'
    )


def unregister():
    global draw_handler

    if draw_handler is not None:
        bpy.types.SpaceView3D.draw_handler_remove(draw_handler, 'WINDOW')
        draw_handler = None

    del bpy.types.Scene.edge_overlay_font_size
    del bpy.types.Scene.edge_overlay_precision
    del bpy.types.Scene.edge_overlay_threshold
    del bpy.types.Scene.edge_overlay_mode
    del bpy.types.Scene.edge_overlay_color
    del bpy.types.Scene.edge_overlay_shadow
    del bpy.types.Scene.edge_overlay_outline

    bpy.utils.unregister_class(VIEW3D_PT_edge_overlay)


if __name__ == "__main__":
    register()