from pathlib import Path
import copy
import importlib.util
import sys
import tkinter as tk

from PIL import ImageDraw, ImageTk


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

spec = importlib.util.spec_from_file_location("racecore_v34_for_v35", V34_PATH)
v34 = importlib.util.module_from_spec(spec)
spec.loader.exec_module(v34)

from core.layer_workspace import ordered_references, reconcile_order
from core.multi_selection import SelectionItem
from core.panel_painter import (
    PANEL_LABELS,
    PanelHitTester,
    is_custom_paint_layer,
    is_manual_polygon,
    manual_polygon_layer,
    shape_asset,
)
from core.preview_interaction import logo_assets, vector_assets


V25 = v34.v33.v32.v31.v30.v29.v28.v27.v26.v25
LEGACY = V25.v24


class StudioV35(v34.StudioV34):
    """Klikbare paneelvulling en vrij getekende, bewerkbare kleurvlakken."""

    def __init__(self):
        self.panel_paint_mode = None
        self.manual_panel_points = []
        self.panel_hit_tester = None
        super().__init__()
        self.panel_hit_tester = PanelHitTester(self.pipeline.masks)
        self.title("RaceCore Livery Studio v3.5 - Panel Painter")

    def build_layout(self):
        super().build_layout()
        header = self.winfo_children()[0]
        for child in header.winfo_children():
            if isinstance(child, tk.Label) and "Livery Studio" in child.cget("text"):
                child.configure(text="Livery Studio  v3.5")

        self.design_toolbox.configure(height=620)
        self._toolbox_section("PANELEN INKLEUREN")
        self._toolbox_grid([
            ("PANEEL AANKLIKKEN", self.start_known_panel_paint),
            ("ZELF OMTREKKEN", self.start_manual_panel),
            ("PANEELLĲST...", self.panel_dialog),
        ], "#0F766E")
        tk.Label(
            self.design_toolbox,
            text="Bekend paneel: één klik. Eigen vlak: klik de hoeken en vul.",
            font=("Segoe UI", 8), fg="#94A3B8", bg="#11151D",
            wraplength=246, justify="left",
        ).pack(anchor="w", padx=13, pady=(5, 10))

        viewer = self.preview_label.master
        controls = tk.Frame(viewer, bg="#11151D", bd=1, relief="solid")
        controls.place(relx=.5, y=16, anchor="n")
        controls.place_forget()
        self.panel_draw_controls = controls
        self.panel_draw_text = tk.StringVar(master=self, value="")
        tk.Label(
            controls, textvariable=self.panel_draw_text,
            font=("Segoe UI", 9, "bold"), fg="#F8FAFC", bg="#11151D",
            padx=10,
        ).pack(side="left", pady=6)
        self.manual_undo_button = self._draw_button(
            controls, "PUNT TERUG", self.undo_manual_point, "#334155"
        )
        self.manual_finish_button = self._draw_button(
            controls, "VUL VLAK", self.finish_manual_panel, "#0F766E"
        )
        self._draw_button(controls, "ANNULEREN", self.cancel_panel_paint, "#7F1D1D")

        self.preview_label.bind("<ButtonPress-1>", self.preview_press)
        self.preview_label.bind("<Escape>", lambda _event: self.cancel_panel_paint())
        self.preview_label.bind("<Return>", lambda _event: self.finish_manual_panel())

    @staticmethod
    def _draw_button(parent, text, command, colour):
        button = tk.Button(
            parent, text=text, command=command, font=("Segoe UI", 8, "bold"),
            fg="#F8FAFC", bg=colour, activeforeground="#FFFFFF",
            activebackground="#475569", relief="flat", padx=9, pady=5,
        )
        button.pack(side="left", padx=(0, 4), pady=4)
        return button

    def toggle_design_toolbox(self):
        if self.design_toolbox.winfo_ismapped():
            self.hide_design_toolbox()
        else:
            self.design_toolbox.place(x=18, y=56, width=278, height=620)
            self.design_toolbox.lift()
            self.toolbox_button.configure(text="− TOEVOEGEN")
            self.toolbox_button.lift()

    def start_known_panel_paint(self):
        self.panel_paint_mode = "known"
        self.manual_panel_points = []
        self.hide_design_toolbox()
        self.panel_draw_text.set("KLIK EEN CARROSSERIEPANEEL")
        self.manual_undo_button.pack_forget()
        self.manual_finish_button.pack_forget()
        self.panel_draw_controls.place(relx=.5, y=16, anchor="n")
        self.panel_draw_controls.lift()
        self.preview_label.configure(cursor="crosshair")
        self.preview_label.focus_set()
        self.status.set("Paneelverf actief | klik binnen het gewenste UV-paneel")

    def start_manual_panel(self):
        self.panel_paint_mode = "manual"
        self.manual_panel_points = []
        self.hide_design_toolbox()
        self.focus_mode.set("design")
        self.focus_show_uv.set(True)
        self._refresh_mode_buttons()
        self.sticker_toggle.configure(state="normal")
        self.manual_undo_button.pack(side="left", padx=(0, 4), pady=4)
        self.manual_finish_button.pack(side="left", padx=(0, 4), pady=4)
        self.panel_draw_controls.place(relx=.5, y=16, anchor="n")
        self._update_manual_controls()
        self.panel_draw_controls.lift()
        self.preview_label.configure(cursor="crosshair")
        self.preview_label.focus_set()
        self.show_selection_overlay()
        self.status.set("Zelf omtrekken | klik minimaal drie punten rond het vlak")

    def _update_manual_controls(self):
        count = len(self.manual_panel_points)
        self.panel_draw_text.set(f"HANDMATIG VLAK  •  {count} PUNTEN")
        self.manual_finish_button.configure(
            state="normal" if count >= 3 else "disabled"
        )
        self.manual_undo_button.configure(
            state="normal" if count else "disabled"
        )

    def preview_press(self, event):
        if self.panel_paint_mode == "known":
            point = self.event_to_texture(event)
            if point is not None:
                self.paint_known_panel_at(point)
            return "break"
        if self.panel_paint_mode == "manual":
            point = self.event_to_texture(event)
            if point is not None:
                self.add_manual_point(point)
            return "break"
        return super().preview_press(event)

    def paint_known_panel_at(self, point):
        self.status.set("Paneel herkennen...")
        self.update_idletasks()
        key = self.panel_hit_tester.hit(point)
        if key is None:
            self.status.set("Hier is geen bekend carrosseriepaneel | probeer binnen de UV-rand")
            return None
        self.panel_colours[key] = self.accent.get().upper()
        self.changed()
        self.focus_mode.set("lmu")
        self._refresh_mode_buttons()
        self.sticker_toggle.configure(state="disabled")
        self.cancel_panel_paint(refresh=False)
        self.status.set(
            f"{PANEL_LABELS[key]} gevuld met {self.accent.get().upper()} | Undo is beschikbaar"
        )
        return key

    def add_manual_point(self, point):
        x = max(0.0, min(4096.0, float(point[0])))
        y = max(0.0, min(4096.0, float(point[1])))
        self.manual_panel_points.append((x, y))
        self._update_manual_controls()
        self.show_selection_overlay()
        self.status.set(
            f"{len(self.manual_panel_points)} punten | klik verder of kies VUL VLAK"
        )

    def undo_manual_point(self):
        if self.panel_paint_mode != "manual" or not self.manual_panel_points:
            return
        self.manual_panel_points.pop()
        self._update_manual_controls()
        self.show_selection_overlay()

    def finish_manual_panel(self):
        if self.panel_paint_mode != "manual":
            return
        if len(self.manual_panel_points) < 3:
            self.status.set("Klik eerst minimaal drie punten rond het vlak")
            return
        layer = self.normalise_shape(manual_polygon_layer(
            self.manual_panel_points, self.accent.get(), len(self.shape_layers) + 1
        ))
        self.shape_layers.append(layer)
        self.panel_paint_mode = None
        self.manual_panel_points = []
        self.panel_draw_controls.place_forget()
        self.preview_label.configure(cursor="crosshair")
        self._finish_quick_add(
            "shape", layer,
            "Handmatig vlak gevuld als losse laag"
        )

    def cancel_panel_paint(self, refresh=True):
        was_active = self.panel_paint_mode is not None
        self.panel_paint_mode = None
        self.manual_panel_points = []
        if hasattr(self, "panel_draw_controls"):
            self.panel_draw_controls.place_forget()
        if hasattr(self, "preview_label"):
            self.preview_label.configure(cursor="crosshair")
        if refresh and was_active:
            self.show_selection_overlay()
            self.status.set("Paneelverf geannuleerd")

    @staticmethod
    def _shape_asset(layer):
        return shape_asset(layer, LEGACY.V14.shape_asset)

    def _compose_state_layers(
        self, canvas, state, exclude_stripe=None, exclude_shape=None,
        exclude_logo=None, exclude_text=None, carbon_top_only=False,
    ):
        if not any(is_custom_paint_layer(item) for item in state.get("shapeLayers", [])):
            return super()._compose_state_layers(
                canvas, state, exclude_stripe, exclude_shape,
                exclude_logo, exclude_text, carbon_top_only=carbon_top_only,
            )
        canvas = canvas.convert("RGBA").copy()
        source = self.pipeline.source.load_rgba()
        editable = self.pipeline.masks.editable(
            canvas.size, source, state.get("hiddenOfficialDecalGroups", ())
        )
        collections = {
            "shape": copy.deepcopy(state.get("shapeLayers", [])),
            "stripe": copy.deepcopy(state.get("stripeLayers", [])),
            "text": copy.deepcopy(state.get("textLayers", [])),
            "logo": copy.deepcopy(state.get("logoLayers", [])),
        }
        order = reconcile_order(collections, state.get("layerOrder", []))
        excluded = {
            "shape": exclude_shape, "stripe": exclude_stripe,
            "text": exclude_text, "logo": exclude_logo,
        }
        normalisers = {
            "shape": self.normalise_shape,
            "stripe": self.normalise_stripe,
            "text": self.normalise_text,
        }
        assets = {
            "shape": self._shape_asset,
            "stripe": LEGACY.V13.stripe_asset,
            "text": LEGACY.V17.text_asset,
        }
        for reference in ordered_references(collections, order):
            if excluded[reference.kind] == reference.index:
                continue
            layer = collections[reference.kind][reference.index]
            if reference.kind == "logo":
                if carbon_top_only and not LEGACY.logo_above_carbon(layer):
                    continue
                canvas = self.layer_engine.logos(
                    canvas, [layer], editable, self.normalise_layer,
                    LEGACY.V12.PLACEMENTS,
                )
            else:
                canvas = self.layer_engine.vector_layers(
                    canvas, [layer], editable, normalisers[reference.kind],
                    assets[reference.kind], LEGACY.V13.stripe_instances,
                )
        return canvas

    def reference_assets(self, reference):
        layer = self.layer_collections()[reference.kind][reference.index]
        if reference.kind == "shape" and is_custom_paint_layer(layer):
            return vector_assets(
                layer, (4096, 4096), self.normalise_shape,
                self._shape_asset, LEGACY.V13.stripe_instances,
            )
        return super().reference_assets(reference)

    def sidebar_edit(self):
        reference = self.selected_sidebar_reference()
        if reference is None:
            return
        layer = self.layer_collections()[reference.kind][reference.index]
        if reference.kind == "shape" and is_custom_paint_layer(layer):
            self.inline_properties.load_selected()
            self.status.set(
                "Handmatige verflaag | kleur, positie, grootte en draaiing staan bij Snel aanpassen"
            )
            return
        return super().sidebar_edit()

    def show_selection_overlay(self):
        if self.panel_paint_mode != "manual":
            super().show_selection_overlay()
            self._lift_panel_tools()
            return
        if self.focus_master is None or not hasattr(self, "preview_label"):
            return
        try:
            width = max(1, self.preview_label.winfo_width())
            height = max(1, self.preview_label.winfo_height())
            image, metrics = self.focus_viewport.render(self.focus_master, width, height)
            draw = ImageDraw.Draw(image)
            points = [
                self._texture_point(point, metrics.size)
                for point in self.manual_panel_points
            ]
            if len(points) >= 2:
                draw.line(points, fill="#22D3EE", width=3, joint="curve")
            if len(points) >= 3:
                draw.line((points[-1], points[0]), fill="#A5F3FC", width=2)
            for index, (x, y) in enumerate(points, start=1):
                radius = 6
                draw.ellipse(
                    (x - radius, y - radius, x + radius, y + radius),
                    fill="#F8FAFC", outline="#22D3EE", width=2,
                )
                draw.text((x + 8, y - 12), str(index), fill="#F8FAFC")
            self._publish_preview_image(image)
            self.focus_tools.lift()
            self._lift_panel_tools()
        except (OSError, ValueError, tk.TclError):
            pass

    def _lift_panel_tools(self):
        if hasattr(self, "toolbox_button"):
            self.toolbox_button.lift()
        if hasattr(self, "design_toolbox") and self.design_toolbox.winfo_ismapped():
            self.design_toolbox.lift()
            self.toolbox_button.lift()
        if hasattr(self, "panel_draw_controls") and self.panel_draw_controls.winfo_ismapped():
            self.panel_draw_controls.lift()


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