from pathlib import Path
from PIL import Image, ImageTk, ImageDraw
import hashlib
import importlib.util
import json
import shutil
import tkinter as tk
from tkinter import filedialog, messagebox, ttk


ROOT = Path(__file__).resolve().parents[2]
APP = Path(__file__).resolve().parent
GENERATED = APP / 'generated'
AUTOSAVE = APP / 'autosave.racecore.json'
LIVE_CONFIG = APP / 'live-link-ui.json'
ASSET_DIR = APP / 'asset_library'
ASSET_DB = APP / 'asset_library.json'
V15_PATH = ROOT / 'outputs' / 'RaceCore_Studio_v1.5' / 'racecore_studio_v15.py'
V15_AUTOSAVE = V15_PATH.parent / 'autosave.racecore.json'

spec = importlib.util.spec_from_file_location('racecore_v15', V15_PATH)
v15 = importlib.util.module_from_spec(spec)
spec.loader.exec_module(v15)

for module in (v15, v15.v14, v15.v14.v13, v15.v14.v13.v12,
               v15.v14.v13.v12.v11):
    module.APP = APP
    module.GENERATED = GENERATED
    module.AUTOSAVE = AUTOSAVE
    module.LIVE_CONFIG = LIVE_CONFIG

COLORS = v15.COLORS
CATEGORIES = ('Alle categorieen', 'Teamlogo', 'Sponsor', 'Badge / nummer', 'Overig')


class StudioV16(v15.StudioV15):
    def __init__(self):
        self.assets = []
        self.asset_photo = None
        self.filtered_asset_ids = []
        migrate = not AUTOSAVE.exists() and V15_AUTOSAVE.exists()
        self.load_asset_db()
        super().__init__()
        self.title('RaceCore Livery Studio v1.6 - Asset Library')
        if migrate:
            self.load_path(V15_AUTOSAVE, record=False)
            self.autosave()

    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  v1.6')
        toolbar = self.winfo_children()[1]
        tk.Button(
            toolbar, text='Logo bibliotheek', command=self.asset_library_dialog,
            font=('Segoe UI', 9, 'bold'), fg=COLORS.NAVY, bg='#F9A8D4',
            activebackground='#FBCFE8', relief='flat', padx=14,
        ).pack(side='left', padx=(0, 8), pady=6)

    def load_asset_db(self):
        ASSET_DIR.mkdir(parents=True, exist_ok=True)
        if not ASSET_DB.exists():
            self.assets = []
            return
        try:
            data = json.loads(ASSET_DB.read_text(encoding='utf-8'))
            self.assets = data.get('assets', [])
        except Exception:
            self.assets = []

    def save_asset_db(self):
        ASSET_DIR.mkdir(parents=True, exist_ok=True)
        data = {'schemaVersion': 1, 'assets': self.assets}
        ASSET_DB.write_text(json.dumps(data, indent=2), encoding='utf-8')

    @staticmethod
    def live_widget(owner, name):
        if not hasattr(owner, name):
            return False
        try:
            return bool(getattr(owner, name).winfo_exists())
        except tk.TclError:
            return False

    def refresh_layers(self, select=None):
        if not self.live_widget(self, 'layer_list'):
            if hasattr(self, 'layer_list'):
                delattr(self, 'layer_list')
            return
        super().refresh_layers(select)

    def refresh_stripes(self, select=None):
        if not self.live_widget(self, 'stripe_list'):
            if hasattr(self, 'stripe_list'):
                delattr(self, 'stripe_list')
            return
        super().refresh_stripes(select)

    def refresh_shapes(self, select=None):
        if not self.live_widget(self, 'shape_list'):
            if hasattr(self, 'shape_list'):
                delattr(self, 'shape_list')
            return
        super().refresh_shapes(select)

    def asset_library_dialog(self):
        win = tk.Toplevel(self)
        win.title('RaceCore Logo & Sponsor Bibliotheek')
        win.geometry('980x650')
        win.minsize(850, 580)
        win.configure(bg=COLORS.PANEL)
        win.transient(self)
        win.grab_set()

        top = tk.Frame(win, bg=COLORS.PANEL)
        top.pack(fill='x', padx=22, pady=(18, 10))
        tk.Label(top, text='LOGO & SPONSOR BIBLIOTHEEK', font=('Segoe UI', 15, 'bold'),
                 fg=COLORS.CYAN, bg=COLORS.PANEL).pack(side='left')
        tk.Label(top, text='Lokaal opgeslagen | klaar voor latere community-sync',
                 font=('Segoe UI', 9), fg=COLORS.MUTED,
                 bg=COLORS.PANEL).pack(side='right')

        filters = tk.Frame(win, bg='#101F3C')
        filters.pack(fill='x', padx=22, pady=(0, 10))
        self.asset_search = tk.StringVar()
        self.asset_category = tk.StringVar(value=CATEGORIES[0])
        self.asset_favourites_only = tk.BooleanVar(value=False)
        search = tk.Entry(filters, textvariable=self.asset_search, font=('Segoe UI', 10))
        search.pack(side='left', fill='x', expand=True, padx=10, pady=9)
        search.insert(0, '')
        category = ttk.Combobox(
            filters, textvariable=self.asset_category, values=CATEGORIES,
            state='readonly', width=18,
        )
        category.pack(side='left', padx=(0, 8), pady=9)
        tk.Checkbutton(
            filters, text='Alleen favorieten', variable=self.asset_favourites_only,
            command=self.refresh_assets, font=('Segoe UI', 9, 'bold'),
            fg=COLORS.TEXT, bg='#101F3C', selectcolor='#253656',
            activebackground='#101F3C', activeforeground=COLORS.TEXT,
        ).pack(side='left', padx=(0, 10))
        self.asset_search.trace_add('write', lambda *_args: self.refresh_assets())
        category.bind('<<ComboboxSelected>>', lambda _event: self.refresh_assets())

        body = tk.Frame(win, bg=COLORS.PANEL)
        body.pack(fill='both', expand=True, padx=22)
        left = tk.Frame(body, bg=COLORS.PANEL)
        left.pack(side='left', fill='both', expand=True, padx=(0, 12))
        self.asset_list = tk.Listbox(
            left, font=('Segoe UI', 10), bg='#08152C', fg=COLORS.TEXT,
            selectbackground='#DB2777', relief='flat', activestyle='none',
            exportselection=False,
        )
        self.asset_list.pack(fill='both', expand=True)
        self.asset_list.bind('<<ListboxSelect>>', lambda _event: self.show_selected_asset())
        self.asset_list.bind('<Double-Button-1>', lambda _event: self.add_selected_asset())

        right = tk.Frame(body, bg='#101F3C', width=320)
        right.pack(side='right', fill='y')
        right.pack_propagate(False)
        self.asset_preview = tk.Label(
            right, text='Importeer een transparant logo', font=('Segoe UI', 10),
            fg=COLORS.MUTED, bg='#071326', width=280, height=260,
        )
        self.asset_preview.pack(fill='x', padx=16, pady=(16, 8))
        self.asset_name_label = tk.StringVar(value='Nog geen logo geselecteerd')
        self.asset_meta_label = tk.StringVar(value='')
        tk.Label(right, textvariable=self.asset_name_label, font=('Segoe UI', 11, 'bold'),
                 fg=COLORS.TEXT, bg='#101F3C', wraplength=280,
                 justify='left').pack(anchor='w', padx=16, pady=(3, 1))
        tk.Label(right, textvariable=self.asset_meta_label, font=('Segoe UI', 9),
                 fg=COLORS.MUTED, bg='#101F3C', wraplength=280,
                 justify='left').pack(anchor='w', padx=16, pady=(0, 8))
        tk.Frame(right, bg='#101F3C').pack(fill='both', expand=True)
        tk.Button(
            right, text='TOEVOEGEN AAN LIVERY', command=self.add_selected_asset,
            font=('Segoe UI', 10, 'bold'), fg=COLORS.NAVY, bg=COLORS.CYAN,
            relief='flat', pady=10,
        ).pack(fill='x', padx=16, pady=(0, 6))
        tk.Button(
            right, text='Favoriet aan / uit', command=self.toggle_asset_favourite,
            font=('Segoe UI', 9, 'bold'), fg=COLORS.TEXT, bg='#334155',
            relief='flat', pady=8,
        ).pack(fill='x', padx=16, pady=(0, 6))
        tk.Button(
            right, text='Naam / categorie bewerken', command=self.edit_asset,
            font=('Segoe UI', 9, 'bold'), fg=COLORS.TEXT, bg='#334155',
            relief='flat', pady=8,
        ).pack(fill='x', padx=16, pady=(0, 6))
        tk.Button(
            right, text='Uit bibliotheek verwijderen', command=self.delete_asset,
            font=('Segoe UI', 9, 'bold'), fg='#FECACA', bg='#7F1D1D',
            relief='flat', pady=8,
        ).pack(fill='x', padx=16, pady=(0, 16))

        actions = tk.Frame(win, bg=COLORS.PANEL)
        actions.pack(fill='x', padx=22, pady=16)
        tk.Button(
            actions, text='+ LOGO IMPORTEREN', command=self.import_asset,
            font=('Segoe UI', 10, 'bold'), fg=COLORS.NAVY, bg='#F9A8D4',
            relief='flat', pady=10,
        ).pack(side='left', fill='x', expand=True, padx=(0, 5))
        tk.Button(
            actions, text='SLUITEN', command=win.destroy,
            font=('Segoe UI', 10, 'bold'), fg=COLORS.TEXT, bg='#475569',
            relief='flat', pady=10,
        ).pack(side='left', fill='x', expand=True, padx=(5, 0))
        self.refresh_assets()
        search.focus_set()

    def filtered_assets(self):
        query = self.asset_search.get().strip().lower() if hasattr(self, 'asset_search') else ''
        category = self.asset_category.get() if hasattr(self, 'asset_category') else CATEGORIES[0]
        favourites = self.asset_favourites_only.get() if hasattr(self, 'asset_favourites_only') else False
        result = []
        for asset in self.assets:
            path = ASSET_DIR / asset.get('filename', '')
            if not path.exists():
                continue
            searchable = ' '.join([
                asset.get('name', ''), asset.get('category', ''), asset.get('tags', '')
            ]).lower()
            if query and query not in searchable:
                continue
            if category != CATEGORIES[0] and asset.get('category') != category:
                continue
            if favourites and not asset.get('favourite', False):
                continue
            result.append(asset)
        return result

    def refresh_assets(self, select_id=None):
        if not self.live_widget(self, 'asset_list'):
            return
        current = select_id or self.selected_asset_id()
        result = self.filtered_assets()
        self.filtered_asset_ids = [asset['id'] for asset in result]
        self.asset_list.delete(0, 'end')
        for asset in result:
            star = '[favoriet] ' if asset.get('favourite', False) else ''
            self.asset_list.insert(
                'end', f"{star}{asset.get('name', 'Naamloos')}  |  {asset.get('category', 'Overig')}"
            )
        if result:
            index = self.filtered_asset_ids.index(current) if current in self.filtered_asset_ids else 0
            self.asset_list.selection_set(index)
            self.asset_list.see(index)
            self.show_selected_asset()
        else:
            self.asset_photo = None
            self.asset_preview.configure(image='', text='Geen logo gevonden')
            self.asset_name_label.set('Bibliotheek is leeg')
            self.asset_meta_label.set('Gebruik + Logo importeren om te beginnen.')

    def selected_asset_id(self):
        if not self.live_widget(self, 'asset_list'):
            return None
        selected = self.asset_list.curselection()
        if not selected or selected[0] >= len(self.filtered_asset_ids):
            return None
        return self.filtered_asset_ids[selected[0]]

    def selected_asset(self):
        asset_id = self.selected_asset_id()
        return next((asset for asset in self.assets if asset.get('id') == asset_id), None)

    def show_selected_asset(self):
        asset = self.selected_asset()
        if not asset:
            return
        path = ASSET_DIR / asset['filename']
        try:
            source = Image.open(path).convert('RGBA')
            size = 270
            checker = Image.new('RGBA', (size, size), '#E2E8F0')
            draw = ImageDraw.Draw(checker)
            tile = 18
            for y in range(0, size, tile):
                for x in range(0, size, tile):
                    if (x // tile + y // tile) % 2:
                        draw.rectangle((x, y, x + tile, y + tile), fill='#CBD5E1')
            source.thumbnail((240, 240), Image.Resampling.LANCZOS)
            x, y = (size - source.width) // 2, (size - source.height) // 2
            checker.alpha_composite(source, (x, y))
            self.asset_photo = ImageTk.PhotoImage(checker.convert('RGB'))
            self.asset_preview.configure(image=self.asset_photo, text='', width=size, height=size)
        except Exception as error:
            self.asset_preview.configure(image='', text=str(error))
        self.asset_name_label.set(asset.get('name', 'Naamloos'))
        tags = asset.get('tags', '').strip() or 'geen tags'
        favourite = 'favoriet' if asset.get('favourite', False) else 'geen favoriet'
        self.asset_meta_label.set(f"{asset.get('category', 'Overig')} | {favourite}\n{tags}")

    def import_asset(self):
        path = filedialog.askopenfilename(
            filetypes=[('Logo afbeeldingen', '*.png *.webp'), ('PNG', '*.png')]
        )
        if not path:
            return
        source = Path(path)
        try:
            image = Image.open(source)
            if 'A' not in image.getbands():
                if not messagebox.askyesno(
                    'RaceCore',
                    'Deze afbeelding heeft geen transparante achtergrond. Toch importeren?'
                ):
                    return
            digest = hashlib.sha256(source.read_bytes()).hexdigest()
            existing = next((asset for asset in self.assets if asset.get('hash') == digest), None)
            if existing:
                self.refresh_assets(existing['id'])
                self.status.set('Dit logo stond al in de bibliotheek')
                return
            extension = source.suffix.lower() if source.suffix.lower() in ('.png', '.webp') else '.png'
            filename = f'{digest[:16]}{extension}'
            destination = ASSET_DIR / filename
            shutil.copy2(source, destination)
            asset = {
                'id': digest[:16], 'name': source.stem, 'filename': filename,
                'category': 'Overig', 'tags': '', 'favourite': False,
                'visibility': 'private', 'hash': digest,
            }
            self.assets.append(asset)
            self.save_asset_db()
            self.refresh_assets(asset['id'])
            self.edit_asset(asset['id'])
            self.status.set('Logo toegevoegd aan de bibliotheek')
        except Exception as error:
            messagebox.showerror('RaceCore', str(error))

    def edit_asset(self, asset_id=None):
        if asset_id is None:
            asset = self.selected_asset()
        else:
            asset = next((item for item in self.assets if item.get('id') == asset_id), None)
        if not asset:
            return
        dlg = tk.Toplevel(self)
        dlg.title('Logo gegevens')
        dlg.geometry('440x330')
        dlg.configure(bg=COLORS.PANEL)
        dlg.transient(self)
        dlg.grab_set()
        name = tk.StringVar(value=asset.get('name', ''))
        category = tk.StringVar(value=asset.get('category', 'Overig'))
        tags = tk.StringVar(value=asset.get('tags', ''))
        tk.Label(dlg, text='LOGO GEGEVENS', font=('Segoe UI', 13, 'bold'),
                 fg=COLORS.CYAN, bg=COLORS.PANEL).pack(anchor='w', padx=20, pady=(18, 10))
        for label, variable in [('Naam', name), ('Zoekwoorden', tags)]:
            tk.Label(dlg, text=label, font=('Segoe UI', 9), fg=COLORS.TEXT,
                     bg=COLORS.PANEL).pack(anchor='w', padx=20, pady=(5, 2))
            tk.Entry(dlg, textvariable=variable, font=('Segoe UI', 10)).pack(
                fill='x', padx=20
            )
        tk.Label(dlg, text='Categorie', font=('Segoe UI', 9), fg=COLORS.TEXT,
                 bg=COLORS.PANEL).pack(anchor='w', padx=20, pady=(8, 2))
        ttk.Combobox(
            dlg, textvariable=category, values=CATEGORIES[1:], state='readonly'
        ).pack(fill='x', padx=20)

        def save():
            asset['name'] = name.get().strip() or Path(asset['filename']).stem
            asset['category'] = category.get()
            asset['tags'] = tags.get().strip()
            self.save_asset_db()
            dlg.destroy()
            self.refresh_assets(asset['id'])

        tk.Button(
            dlg, text='OPSLAAN', command=save, font=('Segoe UI', 10, 'bold'),
            fg=COLORS.NAVY, bg=COLORS.CYAN, relief='flat', pady=10,
        ).pack(fill='x', padx=20, pady=18)

    def toggle_asset_favourite(self):
        asset = self.selected_asset()
        if not asset:
            return
        asset['favourite'] = not asset.get('favourite', False)
        self.save_asset_db()
        self.refresh_assets(asset['id'])

    def delete_asset(self):
        asset = self.selected_asset()
        if not asset:
            return
        if not messagebox.askyesno(
            'RaceCore',
            f"'{asset.get('name', 'Dit logo')}' uit de bibliotheek verwijderen?\n\n"
            'Logo-lagen die dit bestand gebruiken kunnen daarna ontbreken.'
        ):
            return
        path = ASSET_DIR / asset.get('filename', '')
        if path.exists():
            path.unlink()
        self.assets.remove(asset)
        self.save_asset_db()
        self.refresh_assets()
        self.status.set('Logo uit bibliotheek verwijderd')

    def add_selected_asset(self):
        asset = self.selected_asset()
        if not asset:
            self.status.set('Kies eerst een logo uit de bibliotheek')
            return
        path = ASSET_DIR / asset['filename']
        if not path.exists():
            self.status.set('Het logobestand ontbreekt')
            return
        layer = self.normalise_layer({
            'id': f"asset-{asset['id']}-{len(self.logo_layers) + 1}",
            'name': asset.get('name', path.stem), 'path': str(path),
            'position': 'Roof / engine cover', 'scale': 55,
        })
        self.logo_layers.append(layer)
        index = len(self.logo_layers) - 1
        self.commit_layers(index, 'Logo uit bibliotheek toegevoegd')
        v15.v14.LogoPlacementEditorV14(self, index)


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