from pathlib import Path
import importlib.util
import sys


APP = Path(__file__).resolve().parent
V28_PATH = APP / "racecore_studio_v28.py"
if str(APP) not in sys.path:
    sys.path.insert(0, str(APP))

spec = importlib.util.spec_from_file_location("racecore_v28_for_v29", V28_PATH)
v28 = importlib.util.module_from_spec(spec)
spec.loader.exec_module(v28)

from core.snap_guides import (
    FERRARI_GUIDES_X,
    FERRARI_GUIDES_Y,
    snap_extent,
)


class StudioV29(v28.StudioV28):
    """Slim vastklikken, hulplijnen en direct centreren."""

    def __init__(self):
        self.snap_enabled = None
        self.active_snap_guides = {"x": None, "y": None}
        super().__init__()
        self.title("RaceCore Livery Studio v2.9 - Smart Guides")

    def build_layout(self):
        super().build_layout()
        header = self.winfo_children()[0]
        for child in header.winfo_children():
            if isinstance(child, v28.v27.v26.v25.tk.Label) and "Livery Studio" in child.cget("text"):
                child.configure(text="Livery Studio  v2.9")
        self.direct_hint.configure(
            text="SLEEP • HOEK = SCHALEN • RONDJE = DRAAIEN • SNAP = STRAK"
        )

        viewer = self.preview_label.master
        self.snap_enabled = v28.v27.v26.v25.tk.BooleanVar(
            master=self, value=True
        )
        tools = v28.v27.v26.v25.tk.Frame(viewer, bg="#0B1730")
        tools.place(relx=1.0, x=-20, y=18, anchor="ne")
        self.snap_tools = tools
        v28.v27.v26.v25.tk.Checkbutton(
            tools, text="SNAP", variable=self.snap_enabled,
            command=self.snap_toggled,
            font=("Segoe UI", 8, "bold"), fg="#A7F3D0", bg="#0B1730",
            activebackground="#0B1730", activeforeground="#A7F3D0",
            selectcolor="#172A4B", padx=7, pady=4,
        ).pack(side="left")
        for text, axis in (("MIDDEN X", "x"), ("MIDDEN Y", "y")):
            v28.v27.v26.v25.tk.Button(
                tools, text=text, command=lambda value=axis: self.align_selected(value),
                font=("Segoe UI", 8, "bold"), fg="#F8FAFC", bg="#334155",
                activebackground="#475569", activeforeground="#F8FAFC",
                relief="flat", padx=8, pady=5,
            ).pack(side="left", padx=(3, 0))
        tools.lift()

    def snap_toggled(self):
        self.active_snap_guides = {"x": None, "y": None}
        self.show_selection_overlay()
        self.status.set(
            "Slim vastklikken aan" if self.snap_enabled.get()
            else "Slim vastklikken uit"
        )

    def preview_press(self, event):
        self.active_snap_guides = {"x": None, "y": None}
        super().preview_press(event)
        if self.direct_drag and self.direct_drag.get("mode") == "move":
            placed = self.selected_preview_asset()
            if placed is not None:
                self.direct_drag["asset_origin"] = (
                    placed.center_x, placed.center_y
                )
                left, top, right, bottom = placed.bounds
                self.direct_drag["snap_origin"] = (
                    (left + right) / 2, (top + bottom) / 2
                )
                self.direct_drag["half_size"] = (
                    (right - left) / 2, (bottom - top) / 2
                )

    def snap_targets(self, exclude_uid):
        guides_x = list(FERRARI_GUIDES_X)
        guides_y = list(FERRARI_GUIDES_Y)
        collections = self.reconcile_layer_order()
        for reference in v28.v27.v26.v25.ordered_references(
            collections, self.layer_order
        ):
            if reference.uid == exclude_uid:
                continue
            layer = collections[reference.kind][reference.index]
            if not layer.get("visible", True):
                continue
            for placed in self.reference_assets(reference):
                left, top, right, bottom = placed.bounds
                guides_x.extend((left, placed.center_x, right))
                guides_y.extend((top, placed.center_y, bottom))
        return guides_x, guides_y

    def preview_drag(self, event):
        drag = self.direct_drag
        if (
            drag is None or drag.get("mode") != "move"
            or not self.snap_enabled.get() or "asset_origin" not in drag
        ):
            self.active_snap_guides = {"x": None, "y": None}
            super().preview_drag(event)
            return
        point = self.event_to_texture(event)
        if point is None:
            return
        reference = self.resolve_layer_uid(drag["uid"])
        if reference is None:
            self.direct_drag = None
            return
        layer = self.layer_collections()[reference.kind][reference.index]
        if layer.get("locked", False):
            self.direct_drag = None
            return

        pointer_dx = point[0] - drag["start"][0]
        pointer_dy = point[1] - drag["start"][1]
        asset_x, asset_y = drag["asset_origin"]
        snap_x, snap_y = drag["snap_origin"]
        desired_x, desired_y = snap_x + pointer_dx, snap_y + pointer_dy
        half_width, half_height = drag["half_size"]
        guides_x, guides_y = self.snap_targets(reference.uid)
        snapped_x = snap_extent(desired_x, half_width, guides_x)
        snapped_y = snap_extent(desired_y, half_height, guides_y)
        self.active_snap_guides = {
            "x": snapped_x.guide,
            "y": snapped_y.guide,
        }

        delta_x = int(round(snapped_x.value - snap_x))
        delta_y = int(round(snapped_y.value - snap_y))
        origin_x, origin_y = drag["origin"]
        instance = drag["instance"]
        if reference.kind == "logo":
            self.move_logo(layer, instance, origin_x, origin_y, delta_x, delta_y)
        else:
            layer["centerX"] = max(0, min(4096, origin_x + delta_x))
            direction = -1 if layer.get("paired", False) and instance > 0 else 1
            layer["centerY"] = max(0, min(4096, origin_y + direction * delta_y))

        drag["moved"] = drag["moved"] or bool(delta_x or delta_y)
        self.schedule_preview()
        self.show_selection_overlay()
        snapped = snapped_x.snapped or snapped_y.snapped
        self.status.set(
            "Vastgeklikt op hulplijn" if snapped
            else f"Verplaatsen: {delta_x:+d}, {delta_y:+d}"
        )

    def preview_release(self, event):
        had_guides = any(value is not None for value in self.active_snap_guides.values())
        self.active_snap_guides = {"x": None, "y": None}
        super().preview_release(event)
        if had_guides:
            self.show_selection_overlay()

    def align_selected(self, axis):
        target = self.selected_transform_target()
        if target is None:
            self.status.set("Kies eerst een ontgrendeld object")
            return
        reference, layer, placed = target
        instance = placed.instance_index
        if reference.kind == "logo":
            key = "x" if axis == "x" else "y"
            if layer.get("pairMode") == "separate":
                offsets = list(layer.get("pairOffsets", []))
                while len(offsets) <= instance:
                    offsets.append({"x": 0, "y": 0})
                offsets[instance] = dict(offsets[instance])
                offsets[instance][key] = 0
                layer["pairOffsets"] = offsets
            else:
                layer["offsetX" if axis == "x" else "offsetY"] = 0
        elif axis == "x":
            layer["centerX"] = 2048
        elif layer.get("paired", False) and instance > 0:
            layer["centerY"] = 4640 - 2048
        else:
            layer["centerY"] = 2048

        self.record_state()
        self.autosave()
        self.schedule_preview()
        self.refresh_layer_sidebar(reference.uid)
        self.status.set(
            "Horizontaal gecentreerd" if axis == "x"
            else "Verticaal gecentreerd"
        )

    def draw_additional_guides(self, draw, image, scale_x, scale_y):
        guide_x = self.active_snap_guides.get("x")
        guide_y = self.active_snap_guides.get("y")
        colour = "#67E8F9"
        if guide_x is not None:
            x = round(guide_x * scale_x)
            for y in range(0, image.height, 18):
                draw.line((x, y, x, min(y + 10, image.height)), fill=colour, width=2)
        if guide_y is not None:
            y = round(guide_y * scale_y)
            for x in range(0, image.width, 18):
                draw.line((x, y, min(x + 10, image.width), y), fill=colour, width=2)


if __name__ == "__main__":
    StudioV29().mainloop()
