from pathlib import Path
from PIL import Image, ImageTk, ImageChops, ImageOps
import importlib.util, json, subprocess, sys, tkinter as tk
from tkinter import filedialog, messagebox, ttk

ROOT=Path(__file__).resolve().parents[2]; APP=Path(__file__).resolve().parent; GENERATED=APP/'generated'
BLANK_SOURCE=ROOT/'outputs'/'Blank_Canvas_Engine_v1.0'/'generated'/'blank_source.tga'
V08_PATH=ROOT/'outputs'/'RaceCore_Studio_UI_v0.8'/'racecore_studio_v08.py'
spec=importlib.util.spec_from_file_location('racecore_v08',V08_PATH); v08=importlib.util.module_from_spec(spec); spec.loader.exec_module(v08)
LIVE_CONFIG=APP/'live-link-ui.json'

PLACEMENTS={
    'Roof / engine cover': [(2090,2440,0)],
    'Side panels (paired)': [(2050,1220,0),(2050,3420,180)],
    'Rear wing': [(3370,315,180)],
    'Hood': [(3310,2470,90)],
}

class StudioV09(v08.StudioV08):
    def __init__(self):
        self.logo_path=''; self.logo_position='Roof / engine cover'; self.logo_scale=55; self.logo_enabled=False; self.blank_mode=False
        super().__init__(); self.title('RaceCore Livery Studio v0.9 - Ferrari 296')

    def build_layout(self):
        super().build_layout()
        self.logo_label=tk.StringVar(value='Geen logo gekozen')
        toolbar=self.winfo_children()[1]
        tk.Button(toolbar,text='Nieuw blanco',command=self.new_blank_project,font=('Segoe UI',9,'bold'),fg=v08.base.TEXT,bg='#475569',activebackground='#64748b',relief='flat',padx=14).pack(side='left',padx=(8,0),pady=6)
        tk.Button(toolbar,text='Sponsor / Logo',command=self.logo_dialog,font=('Segoe UI',9,'bold'),fg=v08.base.NAVY,bg=v08.base.CYAN,activebackground='#67e8f9',relief='flat',padx=14).pack(side='left',padx=8,pady=6)

    def new_blank_project(self):
        self.blank_mode=True; self.logo_enabled=False; self.logo_path=''; self.logo_position='Roof / engine cover'; self.logo_scale=55
        self.primary.set('#FFFFFF'); self.accent.set('#FFFFFF'); self.width.set(100); self.preset.set('Clean Center')
        self.logo_label.set('Geen logo gekozen'); self.record_state(); self.autosave(); self.generate(False); self.status.set('Nieuw blanco project')

    def logo_dialog(self):
        win=tk.Toplevel(self); win.title('Sponsor & Logo'); win.geometry('430x360'); win.configure(bg=v08.base.PANEL); win.transient(self); win.grab_set()
        tk.Label(win,text='SPONSOR & LOGO',font=('Segoe UI',14,'bold'),fg=v08.base.CYAN,bg=v08.base.PANEL).pack(anchor='w',padx=22,pady=(20,14))
        tk.Label(win,textvariable=self.logo_label,font=('Segoe UI',9),fg=v08.base.MUTED,bg=v08.base.PANEL,wraplength=380,justify='left').pack(anchor='w',padx=22)
        tk.Button(win,text='Kies transparante PNG',command=self.choose_logo,font=('Segoe UI',10,'bold'),fg=v08.base.TEXT,bg='#334155',relief='flat',pady=8).pack(fill='x',padx=22,pady=12)
        tk.Label(win,text='Plaatsing',font=('Segoe UI',10),fg=v08.base.TEXT,bg=v08.base.PANEL).pack(anchor='w',padx=22)
        pos=tk.StringVar(value=self.logo_position); combo=ttk.Combobox(win,textvariable=pos,values=list(PLACEMENTS),state='readonly'); combo.pack(fill='x',padx=22,pady=(4,10))
        tk.Label(win,text='Schaal',font=('Segoe UI',10),fg=v08.base.TEXT,bg=v08.base.PANEL).pack(anchor='w',padx=22)
        scale=tk.IntVar(value=self.logo_scale); tk.Scale(win,from_=20,to=100,variable=scale,orient='horizontal',bg=v08.base.PANEL,fg=v08.base.TEXT,troughcolor='#253656',highlightthickness=0).pack(fill='x',padx=18)
        enabled=tk.BooleanVar(value=self.logo_enabled); tk.Checkbutton(win,text='Logo inschakelen',variable=enabled,font=('Segoe UI',10),fg=v08.base.TEXT,bg=v08.base.PANEL,selectcolor='#253656',activebackground=v08.base.PANEL).pack(anchor='w',padx=18,pady=8)
        def apply_dialog():
            self.logo_position=pos.get(); self.logo_scale=scale.get(); self.logo_enabled=enabled.get() and bool(self.logo_path); self.changed(); win.destroy()
        actions=tk.Frame(win,bg=v08.base.PANEL); actions.pack(fill='x',padx=22,pady=10)
        tk.Button(actions,text='VERWIJDER LOGO',command=lambda:self.remove_logo(win),font=('Segoe UI',9,'bold'),fg='#fecaca',bg='#7f1d1d',activebackground='#991b1b',relief='flat',pady=10).pack(side='left',fill='x',expand=True,padx=(0,5))
        tk.Button(actions,text='TOEPASSEN',command=apply_dialog,font=('Segoe UI',10,'bold'),fg=v08.base.NAVY,bg=v08.base.CYAN,relief='flat',pady=10).pack(side='left',fill='x',expand=True,padx=(5,0))

    def choose_logo(self):
        path=filedialog.askopenfilename(filetypes=[('Transparante PNG','*.png')])
        if path:
            try:
                im=Image.open(path)
                if 'A' not in im.getbands(): messagebox.showwarning('RaceCore','Deze PNG heeft geen transparantiekanaal. Hij kan een rechthoekige achtergrond tonen.')
                self.logo_path=path; self.logo_label.set(Path(path).name)
            except Exception as e: messagebox.showerror('RaceCore',str(e))

    def remove_logo(self,dialog=None):
        self.logo_enabled=False; self.logo_path=''; self.logo_position='Roof / engine cover'; self.logo_scale=55
        self.logo_label.set('Geen logo gekozen')
        self.changed()
        self.status.set('Logo verwijderd - preview bijgewerkt')
        if dialog is not None: dialog.destroy()

    def snapshot(self):
        s=super().snapshot(); s['blankMode']=self.blank_mode; s['logo']={'enabled':self.logo_enabled,'path':self.logo_path,'position':self.logo_position,'scale':self.logo_scale}; return s
    def apply_state(self,state,record=False):
        self.blank_mode=state.get('blankMode',False)
        logo=state.get('logo',{}); self.logo_enabled=logo.get('enabled',False); self.logo_path=logo.get('path',''); self.logo_position=logo.get('position','Roof / engine cover'); self.logo_scale=logo.get('scale',55)
        if hasattr(self,'logo_label'): self.logo_label.set(Path(self.logo_path).name if self.logo_path else 'Geen logo gekozen')
        super().apply_state(state,record)

    def _worker(self,apply):
        try:
            # Laat v0.8 eerst lak, preset en semantische bescherming bouwen.
            previous_source=v08.base.SOURCE
            if self.blank_mode: v08.base.SOURCE=BLANK_SOURCE
            try: super()._worker(False)
            finally: v08.base.SOURCE=previous_source
            src=v08.GENERATED/'customskin.tga'; canvas=Image.open(src).convert('RGBA'); size=canvas.size
            if self.logo_enabled and self.logo_path:
                logo=Image.open(self.logo_path).convert('RGBA')
                max_width=round(720*self.logo_scale/100); logo.thumbnail((max_width,round(max_width*.65)),Image.Resampling.LANCZOS)
                editable=ImageChops.subtract(v08.base.load_l('carbon.png'),self.protected_mask(size))
                for cx,cy,rotation in PLACEMENTS[self.logo_position]:
                    item=logo.rotate(rotation,expand=True,resample=Image.Resampling.BICUBIC)
                    layer=Image.new('RGBA',size,(0,0,0,0)); x=round(cx-item.width/2); y=round(cy-item.height/2); layer.alpha_composite(item,(x,y))
                    alpha=ImageChops.multiply(layer.getchannel('A'),editable); layer.putalpha(alpha); canvas=Image.alpha_composite(canvas,layer)
            GENERATED.mkdir(parents=True,exist_ok=True); rgb=canvas.convert('RGB'); rgb.save(GENERATED/'customskin.tga',format='TGA',compression=None); Image.new('RGB',size,(0,0,0)).save(GENERATED/'customskin_region.tga',format='TGA',compression=None)
            p=rgb.copy(); p.thumbnail((880,680)); p.save(GENERATED/'preview.png',optimize=True)
            label='Preview met logo gereed' if self.logo_enabled else 'Preview gereed'
            if apply:
                result=subprocess.run([sys.executable,str(v08.base.LIVE_LINK),str(LIVE_CONFIG)],capture_output=True,text=True,timeout=60)
                if result.returncode: raise RuntimeError(result.stderr.strip() or result.stdout.strip())
                event=json.loads(result.stdout); label='Live in LMU' if event['status']=='installed' else 'LMU is al bijgewerkt'
            self.after(0,lambda:self.show_preview(label))
        except Exception as e:self.after(0,lambda text=str(e):self.show_error(text))

    def protected_mask(self,size):
        p=Image.new('L',size,0)
        for n in ['number_plates.png','class_stickers.png','car_stickers.png','display_panels.png']: p=ImageChops.lighter(p,v08.base.load_l(n))
        return p

    def show_preview(self,label):
        path=GENERATED/'preview.png'
        if not path.exists(): return
        im=Image.open(path); self.preview_photo=ImageTk.PhotoImage(im); self.preview_label.configure(image=self.preview_photo,text=''); self.status.set(label)

if __name__=='__main__':StudioV09().mainloop()
