"""Echte Glas-Optik fuer Tkinter: vorgerenderte Panel-Bilder.

Tkinter kann keine Transparenz zwischen Widgets — Glassmorphism wird
hier mit PIL als Bild gerendert (weicher Schatten, Lichtkante,
Vertikalverlauf, Accent-Glow) und als Hintergrund-Label unter den
Inhalt gelegt. Der Inhalt liegt in einer zweiten Schicht im selben
Grid-Feld darueber; seine Mitte hat exakt die Panel-Farbe, sodass
nur Schatten und Kante sichtbar bleiben.

Bilder werden nach (Art, Groesse, Farben) gecacht und bei Resize
entprellt neu gerendert.
"""
import customtkinter
from PIL import Image, ImageDraw, ImageFilter, ImageTk

from src.ui import theme

_cache = {}


def _rounded(draw, box, radius, fill):
    draw.rounded_rectangle(box, radius=radius, fill=fill)


def renderPanel(width, height, radius=18, top='#1B2436', bottom='#141C2B',
                edge='#3D5170', accent=None, shadowRgb=(0, 0, 0),
                shadowAlpha=150):
    """Milchglas-Karte: Schatten + Verlauf + Lichtkante oben."""
    key = ('panel', width, height, radius, top, bottom, edge, accent,
           shadowRgb, shadowAlpha)
    if key in _cache:
        return _cache[key]
    shadow = shadowAlpha > 0
    pad = 16 if shadow else 2
    image = Image.new('RGBA', (width, height), (0, 0, 0, 0))
    panel_box = [pad, pad - 4, width - pad, height - pad]
    if shadow:
        glow = Image.new('RGBA', (width, height), (0, 0, 0, 0))
        _rounded(ImageDraw.Draw(glow), panel_box, radius,
                 (*shadowRgb, min(255, shadowAlpha)))
        glow = glow.filter(ImageFilter.GaussianBlur(10))
        image.alpha_composite(glow, (0, 5))
    # Vertikalverlauf der Flaeche
    body = Image.new('RGBA', (width, height), (0, 0, 0, 0))
    gradient = Image.new('RGB', (1, 256))
    for y in range(256):
        t = y / 255
        gradient.putpixel((0, y), tuple(
            round(int(top[i:i + 2], 16) +
                  (int(bottom[i:i + 2], 16) - int(top[i:i + 2], 16)) * t)
            for i in (1, 3, 5)))
    gradient = gradient.resize(
        (panel_box[2] - panel_box[0], panel_box[3] - panel_box[1]))
    mask = Image.new('L', gradient.size, 0)
    _rounded(ImageDraw.Draw(mask), [0, 0, *gradient.size], radius, 255)
    body.paste(gradient, panel_box[:2], mask)
    if accent:
        # Accent-Schleier entlang der Oberkante
        veil = Image.new('RGBA', (width, height), (0, 0, 0, 0))
        _rounded(ImageDraw.Draw(veil), panel_box, radius,
                 (*_rgb(accent), 26))
        veil = veil.filter(ImageFilter.GaussianBlur(14))
        veil.putalpha(veil.getchannel('A').point(
            lambda a: a if a < 26 else 26))
        body.alpha_composite(veil, (0, -6))
    image.alpha_composite(body)
    # Lichtkante: 1px heller Strich oben
    rim = ImageDraw.Draw(image)
    rim.arc([panel_box[0], panel_box[1], panel_box[0] + radius * 2,
             panel_box[1] + radius * 2], 90, 180, fill=edge, width=2)
    rim.arc([panel_box[2] - radius * 2, panel_box[1], panel_box[2],
             panel_box[1] + radius * 2], 0, 90, fill=edge, width=2)
    rim.line([panel_box[0] + radius, panel_box[1] + 1,
              panel_box[2] - radius, panel_box[1] + 1], fill=edge, width=2)
    photo = ImageTk.PhotoImage(image)
    _cache[key] = photo
    return photo


def renderGradient(width, height, top, bottom, glow=None, glowAt=(0.5, 0.9),
                   glowRadius=0.7, glowAlpha=60):
    """Flaechen-Verlauf mit optionalem Accent-Glow (Sidebar/Header)."""
    key = ('grad', width, height, top, bottom, glow, glowAt, glowRadius)
    if key in _cache:
        return _cache[key]
    image = Image.new('RGB', (1, 256))
    for y in range(256):
        t = y / 255
        image.putpixel((0, y), tuple(
            round(int(top[i:i + 2], 16) +
                  (int(bottom[i:i + 2], 16) - int(top[i:i + 2], 16)) * t)
            for i in (1, 3, 5)))
    image = image.resize((width, height)).convert('RGBA')
    if glow:
        layer = Image.new('RGBA', (width, height), (0, 0, 0, 0))
        gx, gy = int(width * glowAt[0]), int(height * glowAt[1])
        radius = int(max(width, height) * glowRadius)
        ImageDraw.Draw(layer).ellipse(
            [gx - radius, gy - radius, gx + radius, gy + radius],
            fill=(*_rgb(glow), glowAlpha))
        layer = layer.filter(ImageFilter.GaussianBlur(radius // 2))
        image.alpha_composite(layer)
    photo = ImageTk.PhotoImage(image)
    _cache[key] = photo
    return photo


def _rgb(hexColor):
    return tuple(int(hexColor[i:i + 2], 16) for i in (1, 3, 5))


class GlassPanel(customtkinter.CTkFrame):
    """Karte mit Glas-Hintergrundbild; Inhalt liegt in self.body."""

    RADIUS = 18

    def __init__(self, master, accentVeil=False, **kwargs):
        kwargs.setdefault('fg_color', theme.BG)
        super().__init__(master, **kwargs)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self._accentVeil = accentVeil
        self._bgLabel = customtkinter.CTkLabel(self, text='')
        self._bgLabel.grid(row=0, column=0, sticky='nsew')
        self.body = customtkinter.CTkFrame(
            self, fg_color=theme.PANEL_CENTER, corner_radius=self.RADIUS - 6)
        self.body.grid(row=0, column=0, sticky='nsew', padx=14, pady=(10, 16))
        self.body.grid_columnconfigure(0, weight=1)
        self._renderJob = None
        self.bind('<Configure>', self._scheduleRender)

    def _scheduleRender(self, _event):
        if self._renderJob is not None:
            self.after_cancel(self._renderJob)
        self._renderJob = self.after(120, self._render)

    def _render(self):
        self._renderJob = None
        width, height = self.winfo_width(), self.winfo_height()
        if width < 40 or height < 40:
            return
        image = renderPanel(
            width, height, radius=self.RADIUS,
            top=theme.PANEL_TOP, bottom=theme.PANEL_BOTTOM,
            edge=theme.PANEL_EDGE,
            shadowRgb=theme.SHADOW_RGB,
            shadowAlpha=int(
                theme.SHADOW_ALPHA_BASE * theme.GLASS_INTENSITY / 100),
            accent=theme.ACCENT if self._accentVeil else None)
        self._bgLabel.configure(image=image)
        self._bgLabel.image = image  # Referenz gegen GC
