#!/usr/bin/env python3
"""Generate textures for the premium notification dialog style (75% size).

Outputs (resources/media/):
    notif_card_fill.png     - 9-slice card background (white rounded rect)
    notif_card_stroke.png   - 9-slice card border (white rounded outline)
    notif_thumb_mask.png    - diffuse mask for the episode thumbnail control
    notif_icon_info.png     - (i) icon
    notif_icon_play.png     - play triangle icon
    notif_icon_close.png    - X icon
    notif_button_fill.png   - 9-slice action button background (radius 24)
    notif_button_stroke.png - 9-slice action button border
    notif_pill_small_fill.png   - 9-slice small pill background
    notif_pill_small_stroke.png - 9-slice small pill border
    notif_circle_fill.png   - circular button background
    notif_circle_stroke.png - circular button border
    notif_progress_fill.png - countdown progress fill (pill, 9-slice)
"""
import os
import sys

from PIL import Image, ImageDraw, ImageFont

OUT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__)))
SS = 4  # supersampling

KODI_FONT = os.environ.get(
    'KODI_FONT',
    '/Applications/Kodi.app/Contents/Resources/Kodi/addons/skin.estuary/fonts/NotoSans-Regular.ttf',
)


def save(img, name):
    path = os.path.join(OUT_DIR, name)
    img.save(path, 'PNG')
    print(f"  {name} {img.size[0]}x{img.size[1]}")


def downsample(img, size):
    return img.resize(size, Image.LANCZOS)


def card_fill():
    w, h, radius = 240, 240, 36
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.rounded_rectangle([0, 0, w * SS - 1, h * SS - 1], radius=radius * SS, fill=(255, 255, 255, 255))
    save(downsample(img, (w, h)), 'notif_card_fill.png')


def card_stroke():
    w, h, radius, stroke = 240, 240, 36, 2
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    half = stroke * SS / 2
    d.rounded_rectangle(
        [half, half, w * SS - 1 - half, h * SS - 1 - half],
        radius=radius * SS - half,
        outline=(255, 255, 255, 255),
        width=stroke * SS,
    )
    save(downsample(img, (w, h)), 'notif_card_stroke.png')


def thumb_mask():
    """Thumbnail mask 170x153 skin px. Radius 24 = 2/3 of the card radius (36), the same as the action
    buttons, so every element nested in the card shares one corner size.

    White RGB with the shape in ALPHA (a greyscale mask renders black corners). The XML uses
    <aspectratio scalediffuse="false">scale</aspectratio>, so Kodi maps the mask onto the control
    rect and the corners are never cropped. 2x for crisp edges above 1080p; the 1-texel
    Gaussian keeps the corner anti-aliased when sampled down (same recipe as
    search_poster_mask.png in generate_search_dialog_textures.py)."""
    from PIL import ImageFilter
    scale = 2
    w, h, radius = 170 * scale, 153 * scale, 24 * scale
    alpha = Image.new('L', (w * SS, h * SS), 0)
    ImageDraw.Draw(alpha).rounded_rectangle([0, 0, w * SS - 1, h * SS - 1], radius=radius * SS, fill=255)
    mask = Image.new('RGBA', (w, h), (255, 255, 255, 255))
    mask.putalpha(downsample(alpha, (w, h)).filter(ImageFilter.GaussianBlur(1.0)))
    save(mask, 'notif_thumb_mask.png')


def icon_info():
    size = 30
    img = Image.new('RGBA', (size * SS, size * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    stroke = 2 * SS
    d.ellipse([stroke // 2, stroke // 2, size * SS - 1 - stroke // 2, size * SS - 1 - stroke // 2],
              outline=(255, 255, 255, 255), width=stroke)
    font = ImageFont.truetype(KODI_FONT, int(size * SS * 0.56))
    text = 'i'
    bbox = d.textbbox((0, 0), text, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    d.text(((size * SS - tw) / 2 - bbox[0], (size * SS - th) / 2 - bbox[1] - size * SS * 0.02),
           text, font=font, fill=(255, 255, 255, 255))
    save(downsample(img, (size, size)), 'notif_icon_info.png')


def icon_play():
    w, h = 28, 24
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.polygon([(0, 0), (0, h * SS - 1), (w * SS - 1, h * SS // 2)], fill=(255, 255, 255, 255))
    save(downsample(img, (w, h)), 'notif_icon_play.png')


def icon_close():
    size = 20
    img = Image.new('RGBA', (size * SS, size * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    stroke = 4 * SS
    inset = stroke // 2 + 1
    d.line([inset, inset, size * SS - inset, size * SS - inset], fill=(255, 255, 255, 255),
           width=stroke)
    d.line([size * SS - inset, inset, inset, size * SS - inset], fill=(255, 255, 255, 255),
           width=stroke)
    save(downsample(img, (size, size)), 'notif_icon_close.png')


def button_fill():
    # Action buttons (Info / Hrat hru / Ukoncit / Prehrat): radius 24 = 2/3 of the card radius
    # (36), ~1/3 of the 70 px height; nested inside the card, so smaller than it. Only the
    # round close button keeps a full circle.
    w, h, radius = 200, 70, 24
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.rounded_rectangle([0, 0, w * SS - 1, h * SS - 1], radius=radius * SS, fill=(255, 255, 255, 255))
    save(downsample(img, (w, h)), 'notif_button_fill.png')


def button_stroke():
    w, h, radius, stroke = 200, 70, 24, 2
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    half = stroke * SS / 2
    d.rounded_rectangle(
        [half, half, w * SS - 1 - half, h * SS - 1 - half],
        radius=radius * SS - half,
        outline=(255, 255, 255, 255),
        width=stroke * SS,
    )
    save(downsample(img, (w, h)), 'notif_button_stroke.png')


def pill_small_fill():
    w, h, radius = 200, 34, 17
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.rounded_rectangle([0, 0, w * SS - 1, h * SS - 1], radius=radius * SS, fill=(255, 255, 255, 255))
    save(downsample(img, (w, h)), 'notif_pill_small_fill.png')


def pill_small_stroke():
    w, h, radius, stroke = 200, 34, 17, 2
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    half = stroke * SS / 2
    d.rounded_rectangle(
        [half, half, w * SS - 1 - half, h * SS - 1 - half],
        radius=radius * SS - half,
        outline=(255, 255, 255, 255),
        width=stroke * SS,
    )
    save(downsample(img, (w, h)), 'notif_pill_small_stroke.png')


def circle_fill():
    size = 69
    img = Image.new('RGBA', (size * SS, size * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.ellipse([0, 0, size * SS - 1, size * SS - 1], fill=(255, 255, 255, 255))
    save(downsample(img, (size, size)), 'notif_circle_fill.png')


def circle_stroke():
    size, stroke = 69, 2
    img = Image.new('RGBA', (size * SS, size * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    half = stroke * SS / 2
    d.ellipse([half, half, size * SS - 1 - half, size * SS - 1 - half],
              outline=(255, 255, 255, 255), width=stroke * SS)
    save(downsample(img, (size, size)), 'notif_circle_stroke.png')


def progress_fill():
    w, h, radius = 200, 10, 5
    img = Image.new('RGBA', (w * SS, h * SS), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.rounded_rectangle([0, 0, w * SS - 1, h * SS - 1], radius=radius * SS, fill=(255, 255, 255, 255))
    save(downsample(img, (w, h)), 'notif_progress_fill.png')


def main():
    print("Generating premium notification textures (75% size):")
    card_fill()
    card_stroke()
    thumb_mask()
    icon_info()
    icon_play()
    icon_close()
    button_fill()
    button_stroke()
    pill_small_fill()
    pill_small_stroke()
    circle_fill()
    circle_stroke()
    progress_fill()
    print("Done.")


if __name__ == '__main__':
    sys.exit(main())
