#!/usr/bin/env python3
"""生成品牌 PNG/ICO(Pillow),供 Chrome 快捷方式与 manifest 使用.

中控用通用监控图标;三所各自用交易所标识色+字标.
"""
from __future__ import annotations

import os
import shutil

REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT = os.path.join(REPO, "brand", "icons")

BG = (12, 16, 25, 255)
PANEL = (20, 27, 45, 255)
CYAN = (34, 211, 238, 255)
GREEN = (52, 211, 153, 255)
RED = (248, 113, 113, 255)

EXCHANGES = {
    "binance": {
        "label": "B",
        "accent": (240, 185, 11, 255),
        "panel": (26, 22, 10, 255),
        "svg_fill": "#F0B90B",
    },
    "okx": {
        "label": "OKX",
        "accent": (255, 255, 255, 255),
        "panel": (18, 18, 18, 255),
        "svg_fill": "#FFFFFF",
    },
    "gate": {
        "label": "G",
        "accent": (23, 230, 161, 255),
        "panel": (10, 28, 24, 255),
        "svg_fill": "#17E6A1",
    },
}


def _lerp(c1: tuple[int, ...], c2: tuple[int, ...], t: float) -> tuple[int, int, int, int]:
    t = max(0.0, min(1.0, t))
    return tuple(int(c1[i] + (c2[i] - c1[i]) * t) for i in range(4))  # type: ignore


def _rounded_rect(draw, box, radius: int, fill) -> None:
    draw.rounded_rectangle(box, radius=radius, fill=fill)


def _font(size: int):
    from PIL import ImageFont

    candidates = [
        os.path.join(os.environ.get("WINDIR", r"C:\Windows"), "Fonts", "arialbd.ttf"),
        os.path.join(os.environ.get("WINDIR", r"C:\Windows"), "Fonts", "segoeuib.ttf"),
        "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
        "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
        "/System/Library/Fonts/Supplemental/Arial Bold.ttf",
    ]
    for path in candidates:
        if path and os.path.isfile(path):
            try:
                return ImageFont.truetype(path, size=size)
            except OSError:
                continue
    return ImageFont.load_default()


def render_icon(size: int):
    from PIL import Image, ImageDraw

    img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
    m = max(6, size // 12)
    r = max(8, size // 6)
    _rounded_rect(draw, (m, m, size - m, size - m), r, BG)
    inner = m + max(2, size // 28)
    _rounded_rect(draw, (inner, inner, size - inner, size - inner), max(6, r - 4), PANEL)

    border = max(2, size // 42)
    for i in range(border):
        t0 = i / max(1, border - 1)
        for x in range(inner, size - inner):
            t = (x - inner) / max(1, size - 2 * inner)
            col = _lerp(CYAN, GREEN, (t + t0) * 0.5)
            draw.point((x, inner + i), fill=col)
            draw.point((x, size - inner - 1 - i), fill=col)
        for y in range(inner, size - inner):
            t = (y - inner) / max(1, size - 2 * inner)
            col = _lerp(CYAN, GREEN, (t + t0) * 0.5)
            draw.point((inner + i, y), fill=col)
            draw.point((size - inner - 1 - i, y), fill=col)

    def sx(v: float) -> int:
        return int(v * size / 512)

    def sy(v: float) -> int:
        return int(v * size / 512)

    pts = [(120, 320), (200, 248), (280, 272), (392, 168)]
    scaled = [(sx(x), sy(y)) for x, y in pts]
    draw.line(scaled, fill=CYAN, width=max(2, size // 26), joint="curve")
    ex, ey = scaled[-1]
    draw.ellipse(
        (ex - size // 28, ey - size // 28, ex + size // 28, ey + size // 28),
        fill=GREEN,
    )

    def candle(cx, top, bottom, body_top, body_bottom, color):
        w = max(1, size // 64)
        bh = max(2, size // 32)
        draw.line((cx, top, cx, bottom), fill=color, width=w)
        draw.rounded_rectangle(
            (cx - bh, body_top, cx + bh, body_bottom),
            radius=max(1, bh // 3),
            fill=color,
        )

    candle(sx(182), sy(248), sy(340), sy(268), sy(332), RED)
    candle(sx(282), sy(200), sy(340), sy(220), sy(316), GREEN)

    return img


def render_exchange_icon(size: int, key: str):
    from PIL import Image, ImageDraw

    cfg = EXCHANGES[key]
    accent = cfg["accent"]
    panel = cfg["panel"]
    label = cfg["label"]

    img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
    m = max(6, size // 12)
    r = max(8, size // 6)
    _rounded_rect(draw, (m, m, size - m, size - m), r, BG)
    inner = m + max(2, size // 28)
    _rounded_rect(draw, (inner, inner, size - inner, size - inner), max(6, r - 4), panel)

    if size >= 32:
        border = max(1, size // 48)
        for i in range(border):
            x0 = inner + i
            y0 = inner + i
            x1 = size - inner - 1 - i
            y1 = size - inner - 1 - i
            if x1 <= x0 or y1 <= y0:
                break
            draw.rounded_rectangle(
                (x0, y0, x1, y1),
                radius=max(2, r - 4 - i),
                outline=accent,
            )

    if key == "binance":
        # 币安菱形标识
        cx = cy = size // 2
        s = max(3, int(size * 0.22))
        diamond = [(cx, cy - s), (cx + s, cy), (cx, cy + s), (cx - s, cy)]
        draw.polygon(diamond, fill=accent)
        s2 = max(1, int(s * 0.42))
        if s2 < s:
            inner_d = [(cx, cy - s2), (cx + s2, cy), (cx, cy + s2), (cx - s2, cy)]
            draw.polygon(inner_d, fill=panel)
    elif key == "okx":
        # OKX 四格方块风格(右下留空)
        gap = max(1, size // 48)
        cell = max(2, int(size * 0.16))
        cx = cy = size // 2
        coords = [
            (cx - cell - gap // 2, cy - cell - gap // 2),
            (cx + gap // 2, cy - cell - gap // 2),
            (cx - cell - gap // 2, cy + gap // 2),
        ]
        for x0, y0 in coords:
            draw.rectangle((x0, y0, x0 + cell, y0 + cell), fill=accent)
    else:
        # Gate: 大字 G
        font_size = max(10, int(size * 0.42))
        font = _font(font_size)
        bbox = draw.textbbox((0, 0), label, font=font)
        tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
        x = (size - tw) // 2 - bbox[0]
        y = (size - th) // 2 - bbox[1] - max(0, size // 64)
        draw.text((x, y), label, font=font, fill=accent)

    return img


def write_exchange_svg(key: str, dest_dir: str) -> None:
    cfg = EXCHANGES[key]
    fill = cfg["svg_fill"]
    if key == "binance":
        mark = (
            f'<polygon points="256,150 362,256 256,362 150,256" fill="{fill}"/>'
            f'<polygon points="256,210 302,256 256,302 210,256" fill="#1a160a"/>'
        )
    elif key == "okx":
        mark = (
            f'<rect x="168" y="168" width="72" height="72" rx="10" fill="{fill}"/>'
            f'<rect x="272" y="168" width="72" height="72" rx="10" fill="{fill}"/>'
            f'<rect x="168" y="272" width="72" height="72" rx="10" fill="{fill}"/>'
        )
    else:
        mark = (
            f'<text x="256" y="310" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" '
            f'font-size="220" font-weight="700" fill="{fill}">G</text>'
        )
    svg = f"""<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <rect width="512" height="512" rx="108" fill="#0c1019"/>
  <rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
  <rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="{fill}" stroke-width="12"/>
  {mark}
</svg>
"""
    with open(os.path.join(dest_dir, "icon.svg"), "w", encoding="utf-8", newline="\n") as f:
        f.write(svg)


def _save_set(out_dir: str, render_fn) -> None:
    from PIL import Image

    os.makedirs(out_dir, exist_ok=True)
    sizes = [16, 32, 48, 180, 192, 512]
    images: dict[int, Image.Image] = {}
    for sz in sizes:
        im = render_fn(sz)
        images[sz] = im
        name = "apple-touch-icon.png" if sz == 180 else f"icon-{sz}.png"
        im.save(os.path.join(out_dir, name), format="PNG", optimize=True)

    ico_sizes = [16, 32, 48]
    ico_imgs = [images[s] for s in ico_sizes]
    ico_imgs[0].save(
        os.path.join(out_dir, "favicon.ico"),
        format="ICO",
        sizes=[(s, s) for s in ico_sizes],
        append_images=ico_imgs[1:],
    )


def main() -> None:
    os.makedirs(OUT, exist_ok=True)
    shutil.copy2(os.path.join(REPO, "brand", "icon.svg"), os.path.join(OUT, "icon.svg"))
    _save_set(OUT, render_icon)
    print(f"DONE hub {OUT}")

    for key in EXCHANGES:
        dest = os.path.join(OUT, key)
        os.makedirs(dest, exist_ok=True)
        write_exchange_svg(key, dest)
        _save_set(dest, lambda sz, k=key: render_exchange_icon(sz, k))
        print(f"DONE {key} {dest}")


if __name__ == "__main__":
    main()
