"""PROTOTYP — wegwerfen. Setzt das Logo so auf die Wand, dass es deren Licht und Struktur
übernimmt: als Aufkleber (Schild)."""
import numpy as np
from PIL import Image, ImageDraw, ImageFilter
from scipy import ndimage

from einfaerben import hex_rgb, maske, rgb_lab


def grau(rgba):
    return rgba[..., :3].astype(float).mean(-1)


def saubere_stelle(vorlage_rgba, fl):
    """Sucht eine flache Wandstelle in Flächengröße (volle Deckung, keine Streifen,
    nicht die Logofläche selbst) und gibt deren Hochpass zurück: Struktur ohne Licht."""
    g = grau(vorlage_rgba)
    ok = maske(vorlage_rgba) & (vorlage_rgba[..., 3] > 250)
    w, h = fl["w"], fl["h"]
    glatt = ndimage.gaussian_filter(g, 3)
    kanten = ndimage.gaussian_filter(np.abs(ndimage.sobel(glatt, 0)) + np.abs(ndimage.sobel(glatt, 1)), 2)
    beste, wert = None, np.inf
    H, W = g.shape
    for y in range(0, H - h, 8):
        for x in range(0, W - w, 8):
            if not (x + w < fl["x"] - 20 or x > fl["x"] + fl["w"] + 20 or y + h < fl["y"] - 20 or y > fl["y"] + fl["h"] + 20):
                continue
            if not ok[y:y + h:4, x:x + w:4].all():
                continue
            k = kanten[y:y + h:4, x:x + w:4].mean()
            if k < wert:
                beste, wert = (x, y), k
    if beste is None:
        return np.ones((h, w))
    x, y = beste
    teil = g[y:y + h, x:x + w]
    return teil / ndimage.gaussian_filter(teil, 6)


def licht(vorlage_rgba, fl):
    """Großflächiges Licht der Wand unter der Fläche, relativ zum Median (1 = normale Wand)."""
    g = grau(vorlage_rgba)
    teil = ndimage.gaussian_filter(g, 10)[fl["y"]:fl["y"] + fl["h"], fl["x"]:fl["x"] + fl["w"]]
    return np.clip(teil / np.median(teil), 0.8, 1.06)


def logo_roh(pfad):
    """Logo auf Inhalt beschnitten; eigener_grund = deckender, farbiger Hintergrund (z. B. CER)."""
    lg = Image.open(pfad).convert("RGBA")
    a = np.array(lg).astype(int)
    inhalt = (a[..., 3] > 20) & ~((a[..., 0] > 245) & (a[..., 1] > 245) & (a[..., 2] > 245))
    ys, xs = np.where(inhalt)
    lg = lg.crop((xs.min(), ys.min(), xs.max() + 1, ys.max() + 1))
    a = np.array(lg)
    # Eigener Grund = der Rand ist deckend und überwiegend NICHT weiß (z. B. CERs blaues Quadrat).
    # Nur die Ecken zu prüfen reicht nicht: Schrift, die bis in eine Ecke läuft, täuscht sonst einen Grund vor.
    rand = np.concatenate([a[0], a[-1], a[:, 0], a[:, -1]])
    deckend = (rand[:, 3] > 250).mean() > 0.9
    weiss = (rand[:, :3].min(-1) > 240).mean() > 0.5
    return lg, bool(deckend and not weiss)


def _anwenden(schicht, lichtfeld, struktur, staerke):
    a = np.array(schicht).astype(float)
    faktor = lichtfeld * (1 + staerke * (struktur - 1))
    a[..., :3] = np.clip(a[..., :3] * faktor[..., None], 0, 255)
    return Image.fromarray(a.astype(np.uint8), "RGBA")


def einpassen(logo, fl):
    f = min(fl["w"] / logo.width, fl["h"] / logo.height)
    w, h = max(round(logo.width * f), 1), max(round(logo.height * f), 1)
    return w, h, round(fl["x"] + fl["w"] / 2 - w / 2), round(fl["y"] + fl["h"] / 2 - h / 2)


def als_aufkleber(bild, vorlage_rgba, fl, logo, eigener_grund, staerke=3.0):
    # Schild: Logo mit Rand auf mattem Weiß, sofern es keinen eigenen Grund hat
    if not eigener_grund:
        # Weiß des Logos durchsichtig machen, sonst steht ein hellerer Kasten im matten Schild
        la = np.array(logo).astype(float)
        weissanteil = np.clip((la[..., :3].min(-1) - 225) / 30, 0, 1)
        la[..., 3] *= 1 - weissanteil
        logo = Image.fromarray(la.astype(np.uint8), "RGBA")
        rand = int(max(logo.size) * 0.08)
        schild = Image.new("RGBA", (logo.width + 2 * rand, logo.height + 2 * rand), (244, 244, 240, 255))
        schild.alpha_composite(logo, (rand, rand))
    else:
        schild = logo
    w, h, x, y = einpassen(schild, fl)
    r = max(2, min(w, h) // 10)
    teil = schild.resize((w, h), Image.LANCZOS).filter(ImageFilter.GaussianBlur(0.4))
    form = Image.new("L", (w, h), 0)
    ImageDraw.Draw(form).rounded_rectangle((0, 0, w - 1, h - 1), radius=r, fill=255)
    teil.putalpha(form.filter(ImageFilter.GaussianBlur(0.6)))
    # Licht und Struktur der Wand genau unter dem Schild
    sub = {"x": x, "y": y, "w": w, "h": h}
    teil = _anwenden(teil, licht(vorlage_rgba, sub), saubere_stelle(vorlage_rgba, sub), staerke)
    # Aufkleberkante: oben feines Licht, unten feiner Schatten
    kante = Image.new("RGBA", (w, h), (0, 0, 0, 0))
    d = ImageDraw.Draw(kante)
    d.rounded_rectangle((0, 0, w - 1, h - 1), radius=r, outline=(255, 255, 255, 70), width=1)
    unten = Image.new("RGBA", (w, h), (0, 0, 0, 0))
    ImageDraw.Draw(unten).rounded_rectangle((0, 0, w - 1, h - 1), radius=r, outline=(0, 0, 0, 60), width=1)
    unten = unten.crop((0, h // 2, w, h))
    kante.alpha_composite(unten, (0, h // 2))
    # weicher, kurzer Schatten: der Aufkleber liegt flach auf
    schatten = Image.new("RGBA", bild.size, (0, 0, 0, 0))
    ImageDraw.Draw(schatten).rounded_rectangle((x, y + 1, x + w - 1, y + h), radius=r, fill=(0, 0, 0, 45))
    bild.alpha_composite(schatten.filter(ImageFilter.GaussianBlur(1.2)))
    bild.alpha_composite(teil, (x, y))
    bild.alpha_composite(kante, (x, y))
    return bild
