from pathlib import Path
import importlib.util
import sys

from PIL import Image, ImageDraw, ImageTk


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

spec = importlib.util.spec_from_file_location("racecore_v27_for_v28", V27_PATH)
v27 = importlib.util.module_from_spec(spec)
spec.loader.exec_module(v27)

from core.canvas_transform import (
    LIMITS,
    handle_points,
    hit_handle,
    rotated_value,
    scale_factor,
    scaled_values,
)


class StudioV28(v27.StudioV27):
    """Direct verplaatsen, schalen en draaien met canvas-handgrepen."""

    def __init__(self):
        super().__init__()
        self.title("RaceCore Livery Studio v2.8 - Transform Handles")

    def build_layout(self):
        super().build_layout()
        header = self.winfo_children()[0]
        for child in header.winfo_children():
            if isinstance(child, v27.v26.v25.tk.Label) and "Livery Studio" in child.cget("text"):
                child.configure(text="Livery Studio  v2.8")
        self.direct_hint.configure(
            text="SLEEP = VERPLAATSEN  •  HOEK = SCHALEN  •  RONDJE = DRAAIEN"
        )
        self.preview_label.bind("<Motion>", self.preview_hover)

    def selected_transform_target(self):
        if not self.preview_selected_uid:
            return None
        reference = self.resolve_layer_uid(self.preview_selected_uid)
        if reference is None:
            return None
        layer = self.layer_collections()[reference.kind][reference.index]
        if not layer.get("visible", True) or layer.get("locked", False):
            return None
        assets = self.reference_assets(reference)
        if not assets:
            return None
        instance = min(self.preview_selected_instance, len(assets) - 1)
        return reference, layer, assets[instance]

    def preview_hover(self, event):
        point = self.event_to_texture(event)
        target = self.selected_transform_target()
        cursor = "hand2"
        if point is not None and target is not None:
            handle = hit_handle(*point, target[2].bounds)
            if handle == "rotate":
                cursor = "exchange"
            elif handle:
                cursor = "sizing"
        try:
            self.preview_label.configure(cursor=cursor)
        except v27.v26.v25.tk.TclError:
            self.preview_label.configure(cursor="hand2")

    def preview_press(self, event):
        point = self.event_to_texture(event)
        target = self.selected_transform_target()
        if point is not None and target is not None:
            reference, layer, placed = target
            handle = hit_handle(*point, placed.bounds)
            if handle:
                mode = "rotate" if handle == "rotate" else "resize"
                origin = {
                    key: int(layer.get(key, minimum))
                    for key, (minimum, _maximum) in LIMITS[reference.kind].items()
                } if mode == "resize" else {
                    "rotation": float(layer.get("rotation", 0))
                }
                self.direct_drag = {
                    "mode": mode,
                    "uid": reference.uid,
                    "kind": reference.kind,
                    "instance": placed.instance_index,
                    "handle": handle,
                    "start": point,
                    "center": (placed.center_x, placed.center_y),
                    "origin": origin,
                    "moved": False,
                }
                self.preview_label.focus_set()
                self.status.set(
                    "Sleep om te draaien" if mode == "rotate"
                    else "Sleep de hoek om proportioneel te schalen"
                )
                return
        super().preview_press(event)
        if self.direct_drag is not None:
            self.direct_drag["mode"] = "move"

    def preview_drag(self, event):
        if self.direct_drag is None or self.direct_drag.get("mode") == "move":
            super().preview_drag(event)
            return
        point = self.event_to_texture(event)
        if point is None:
            return
        reference = self.resolve_layer_uid(self.direct_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

        if self.direct_drag["mode"] == "resize":
            factor = scale_factor(
                self.direct_drag["start"], point, self.direct_drag["center"]
            )
            values = scaled_values(
                reference.kind, self.direct_drag["origin"], factor
            )
            layer.update(values)
            detail = f"Schaal {factor * 100:.0f}%"
        else:
            rotation = rotated_value(
                self.direct_drag["origin"]["rotation"],
                self.direct_drag["start"], point, self.direct_drag["center"],
            )
            layer["rotation"] = rotation
            detail = f"Draaiing {rotation}°"

        self.direct_drag["moved"] = True
        self.schedule_preview()
        self.show_selection_overlay()
        self.status.set(detail)

    def preview_release(self, event):
        drag = self.direct_drag
        mode = drag.get("mode") if drag else None
        super().preview_release(event)
        if drag and drag.get("moved") and mode in {"resize", "rotate"}:
            action = "geschaald" if mode == "resize" else "gedraaid"
            self.status.set(
                f"Object {action} • Undo maakt de hele sleepactie ongedaan"
            )

    def show_selection_overlay(self):
        path = self.pipeline.paths.generated / "preview.png"
        placed = self.selected_preview_asset()
        if not path.exists() or placed is None:
            return
        try:
            with Image.open(path) as opened:
                image = opened.convert("RGB")
            draw = ImageDraw.Draw(image)
            scale_x, scale_y = image.width / 4096, image.height / 4096
            self.draw_additional_guides(draw, image, scale_x, scale_y)
            left, top, right, bottom = placed.bounds
            box = (
                round(left * scale_x), round(top * scale_y),
                round(right * scale_x), round(bottom * scale_y),
            )
            draw.rectangle(box, outline="#22D3EE", width=3)

            points = handle_points(placed.bounds)
            display_points = {
                name: (round(x * scale_x), round(y * scale_y))
                for name, (x, y) in points.items()
            }
            top_center = (round((left + right) / 2 * scale_x), round(top * scale_y))
            rotate_point = display_points["rotate"]
            draw.line((top_center, rotate_point), fill="#22D3EE", width=2)

            radius = 6
            for name in ("nw", "ne", "sw", "se"):
                x, y = display_points[name]
                draw.rectangle(
                    (x - radius, y - radius, x + radius, y + radius),
                    fill="#F8FAFC", outline="#22D3EE", width=2,
                )
            rotate_radius = 7
            x, y = rotate_point
            draw.ellipse(
                (x - rotate_radius, y - rotate_radius,
                 x + rotate_radius, y + rotate_radius),
                fill="#22D3EE", outline="#F8FAFC", width=2,
            )
            self.preview_photo = ImageTk.PhotoImage(image)
            self.preview_label.configure(image=self.preview_photo, text="")
            self.direct_hint.lift()
        except (OSError, ValueError):
            pass

    def draw_additional_guides(self, _draw, _image, _scale_x, _scale_y):
        """Uitbreidingspunt voor tijdelijke snap- en uitlijnhulpen."""
        return


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