from __future__ import annotations

import json
from pathlib import Path
from typing import TypeAlias

import numpy as np
from PIL import Image, ImageDraw, ImageFilter, ImageFont

WIDTH = 2560
HEIGHT = 1280
CORNER_RADIUS = 80
ROOT = Path(__file__).resolve().parent
OUT_PATH = ROOT / "cover.png"
ReadableFont: TypeAlias = ImageFont.FreeTypeFont | ImageFont.ImageFont


def make_blob(size: tuple[int, int], color: tuple[int, int, int, int], cx: int, cy: int, rx: int, ry: int) -> Image.Image:
    layer = Image.new("RGBA", size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(layer)
    draw.ellipse([cx - rx, cy - ry, cx + rx, cy + ry], fill=color)
    return layer


def load_font(size: int, *, bold: bool) -> ReadableFont:
    candidates = [
        ("/System/Library/Fonts/Menlo.ttc", 1 if bold else 0),
        ("/System/Library/Fonts/Supplemental/Courier New Bold.ttf", 0),
        ("/Library/Fonts/Arial Unicode.ttf", 0),
    ]
    for path, index in candidates:
        try:
            return ImageFont.truetype(path, size, index=index)
        except OSError:
            continue
    return ImageFont.load_default(size=size)


def draw_text_layer(text: str, x: int, y: int, font: ReadableFont, color: tuple[int, int, int, int]) -> Image.Image:
    layer = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0))
    ImageDraw.Draw(layer).text((x, y), text, font=font, fill=color)
    return layer


def centered_position(draw: ImageDraw.ImageDraw, text: str, font: ReadableFont, y: int) -> tuple[int, int, int]:
    bbox = draw.textbbox((0, 0), text, font=font)
    text_width = bbox[2] - bbox[0]
    text_height = bbox[3] - bbox[1]
    return int((WIDTH - text_width) // 2 - bbox[0]), int(y - bbox[1]), int(text_height)


def main() -> None:
    canvas = Image.new("RGBA", (WIDTH, HEIGHT), (9, 12, 18, 255))

    blobs = [
        ((30, 144, 255, 180), 560, 380, 760, 520, 120),
        ((0, 210, 160, 150), 1880, 820, 820, 480, 120),
        ((160, 80, 255, 140), 1350, 180, 780, 360, 110),
        ((255, 210, 80, 90), 820, 1040, 620, 300, 90),
    ]
    for color, cx, cy, rx, ry, blur in blobs:
        blob = make_blob((WIDTH, HEIGHT), color, cx, cy, rx, ry).filter(ImageFilter.GaussianBlur(radius=blur))
        canvas = Image.alpha_composite(canvas, blob)

    canvas = canvas.filter(ImageFilter.GaussianBlur(radius=7))

    rng = np.random.default_rng(42)
    noise = rng.integers(0, 255, (HEIGHT, WIDTH), dtype=np.uint8)
    grain_alpha = (noise * 0.16).astype(np.uint8)
    grain = Image.fromarray(np.stack([noise, noise, noise, grain_alpha], axis=-1).astype(np.uint8), "RGBA")
    canvas = Image.alpha_composite(canvas, grain)

    title = "LazyClaude"
    subtitle = "Claude Code-native workflow package with hooks, skills, agents, MCP, and LSP"
    title_font = load_font(220, bold=True)
    subtitle_font = load_font(58, bold=False)

    measure = ImageDraw.Draw(Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)))
    title_x, title_y, title_h = centered_position(measure, title, title_font, 445)
    subtitle_x, subtitle_y, _ = centered_position(measure, subtitle, subtitle_font, title_y + title_h + 88)

    for color, blur in [
        ((80, 210, 255, 70), 22),
        ((150, 255, 220, 85), 10),
        ((255, 255, 255, 120), 4),
    ]:
        glow = draw_text_layer(title, title_x, title_y, title_font, color).filter(ImageFilter.GaussianBlur(radius=blur))
        canvas = Image.alpha_composite(canvas, glow)

    canvas = Image.alpha_composite(canvas, draw_text_layer(title, title_x, title_y, title_font, (255, 255, 255, 246)))
    canvas = Image.alpha_composite(canvas, draw_text_layer(subtitle, subtitle_x, subtitle_y, subtitle_font, (218, 232, 240, 220)))

    label_font = load_font(44, bold=False)
    package = json.loads((ROOT / "package.json").read_text(encoding="utf8"))
    label = f"lazyclaude-ai@{package['version']}"
    label_x, label_y, _ = centered_position(measure, label, label_font, 930)
    pill = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0))
    pill_draw = ImageDraw.Draw(pill)
    label_bbox = pill_draw.textbbox((label_x, label_y), label, font=label_font)
    pad_x = 42
    pad_y = 24
    pill_draw.rounded_rectangle(
        [label_bbox[0] - pad_x, label_bbox[1] - pad_y, label_bbox[2] + pad_x, label_bbox[3] + pad_y],
        radius=42,
        fill=(5, 10, 18, 145),
        outline=(255, 255, 255, 42),
        width=2,
    )
    pill_draw.text((label_x, label_y), label, font=label_font, fill=(232, 244, 247, 230))
    canvas = Image.alpha_composite(canvas, pill)

    mask = Image.new("L", (WIDTH, HEIGHT), 0)
    ImageDraw.Draw(mask).rounded_rectangle([(0, 0), (WIDTH - 1, HEIGHT - 1)], radius=CORNER_RADIUS, fill=255)
    canvas.putalpha(mask)
    canvas = canvas.filter(ImageFilter.GaussianBlur(radius=1))
    canvas.save(OUT_PATH, "PNG", dpi=(400, 400))
    print(f"Saved: {OUT_PATH}")
    print(f"Size: {canvas.size}")
    print(f"Mode: {canvas.mode}")


if __name__ == "__main__":
    main()
