#!/usr/bin/env python3
"""
NexusOS action-icon generator.

Builds the icons the XFCE logoff dialog (xfce4-session-logout) and the
Whisker menu command buttons request — shutdown / reboot / log-out /
suspend / hibernate / switch-user / lock-screen / settings — in the
NexusOS palette (white glyph on a deep-purple disc with a lime ring).

Emits one SVG per icon into actions/, rasterizes to
~/.icons/NexusOS/<size>/actions/<name>.png at 16/22/24/32/48/64/128,
then writes the alias copies (xfsm-*, system-suspend-hibernate, and the
settings-manager app-icon names that Whisker's Settings button uses).

Run:    python3 build_actions.py            # SVGs + PNGs + aliases
        python3 build_actions.py --svg-only # just rewrite SVGs
"""

from pathlib import Path
import shutil
import subprocess
import sys

ROOT = Path(__file__).resolve().parent
ACTIONS = ROOT / "actions"
ICONS_OUT = Path.home() / ".icons" / "NexusOS"
SIZES = [16, 22, 24, 32, 48, 64, 128]

# ── colors (mirror gtk-3.0/colors.css) ────────────────────────────────
BODY = "#5e0066"      # brand_purple_dark — disc fill
RING = "#8cc63f"      # brand_green — disc ring
GLYPH = "#f2f2f2"     # text_primary — glyph

# ── master: purple disc + lime ring, viewBox 0 0 128 128 ──────────────
# Glyph area: a ~70px box centered on (64, 64).
DISC = f'  <circle cx="64" cy="64" r="52" fill="{BODY}" ' \
       f'stroke="{RING}" stroke-width="6"/>\n'


def _gear_glyph() -> str:
    """Settings cog: 8 teeth on a white disc with a punched centre hole."""
    teeth = "".join(
        f'  <rect x="57" y="27" width="14" height="21" rx="2" '
        f'transform="rotate({k * 45} 64 64)" fill="{GLYPH}"/>\n'
        for k in range(8)
    )
    return (
        "  <!-- Settings cog -->\n"
        + teeth
        + f'  <circle cx="64" cy="64" r="25" fill="{GLYPH}"/>\n'
        + f'  <circle cx="64" cy="64" r="10" fill="{BODY}"/>\n'
    )


# ── glyph fragments — white, centered on (64, 64) ─────────────────────
GLYPHS = {
    "system-shutdown": f"""\
  <!-- Power symbol: broken ring (gap at top) + stem -->
  <path d="M 55 51 A 22 22 0 1 0 73 51" fill="none" stroke="{GLYPH}"
        stroke-width="10" stroke-linecap="round"/>
  <rect x="59" y="35" width="10" height="31" rx="5" fill="{GLYPH}"/>
""",

    "system-reboot": f"""\
  <!-- Circular arrow -->
  <path d="M 64 40 A 24 24 0 1 1 41 71" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round"/>
  <path d="M 50 32 L 70 40 L 56 56 Z" fill="{GLYPH}"/>
""",

    "system-log-out": f"""\
  <!-- Doorway bracket, open on the right -->
  <path d="M 72 34 L 42 34 L 42 94 L 72 94" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
  <!-- Arrow exiting to the right -->
  <path d="M 56 64 L 92 64" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round"/>
  <path d="M 80 50 L 96 64 L 80 78" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
""",

    "system-suspend": f"""\
  <!-- Crescent moon: big disc minus a disc shifted right -->
  <path d="M 74 33 A 33 33 0 1 0 74 95 A 33 33 0 0 1 74 33 Z"
        fill="{GLYPH}"/>
""",

    "system-hibernate": f"""\
  <!-- Crescent moon + Z -->
  <path d="M 66 39 A 28 28 0 1 0 66 91 A 28 28 0 0 1 66 39 Z"
        fill="{GLYPH}"/>
  <path d="M 78 34 L 99 34 L 78 56 L 99 56" fill="none" stroke="{GLYPH}"
        stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
""",

    "system-switch-user": f"""\
  <!-- Two person silhouettes -->
  <circle cx="78" cy="56" r="13" fill="{GLYPH}"/>
  <path d="M 56 96 Q 56 72 78 72 Q 100 72 100 96 Z" fill="{GLYPH}"/>
  <circle cx="48" cy="60" r="12" fill="{GLYPH}"/>
  <path d="M 28 96 Q 28 76 48 76 Q 60 76 65 84 L 56 88
           Q 56 84 56 96 Z" fill="{GLYPH}"/>
""",

    "system-lock-screen": f"""\
  <!-- Padlock -->
  <path d="M 52 64 L 52 50 A 12 12 0 0 1 76 50 L 76 64" fill="none"
        stroke="{GLYPH}" stroke-width="8" stroke-linecap="round"/>
  <rect x="40" y="62" width="48" height="40" rx="7" fill="{GLYPH}"/>
  <circle cx="64" cy="78" r="6" fill="{BODY}"/>
  <rect x="61" y="80" width="6" height="13" rx="3" fill="{BODY}"/>
""",

    "preferences-desktop": _gear_glyph(),

    # ── Whisker menu application-category glyphs ──────────────────────
    "applications-internet": f"""\
  <!-- Globe -->
  <circle cx="64" cy="64" r="28" fill="none" stroke="{GLYPH}" stroke-width="7"/>
  <ellipse cx="64" cy="64" rx="12" ry="28" fill="none" stroke="{GLYPH}" stroke-width="7"/>
  <line x1="38" y1="55" x2="90" y2="55" stroke="{GLYPH}" stroke-width="7" stroke-linecap="round"/>
  <line x1="38" y1="73" x2="90" y2="73" stroke="{GLYPH}" stroke-width="7" stroke-linecap="round"/>
""",

    "applications-development": f"""\
  <!-- Code chevrons + slash -->
  <path d="M 52 42 L 34 64 L 52 86" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
  <path d="M 76 42 L 94 64 L 76 86" fill="none" stroke="{GLYPH}"
        stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
  <line x1="71" y1="38" x2="57" y2="90" stroke="{GLYPH}"
        stroke-width="8" stroke-linecap="round"/>
""",

    "applications-multimedia": f"""\
  <!-- Play triangle -->
  <path d="M 51 40 L 51 88 L 92 64 Z" fill="{GLYPH}"/>
""",

    "applications-office": f"""\
  <!-- Document with folded corner + text lines -->
  <path d="M 44 32 L 74 32 L 86 44 L 86 96 L 44 96 Z" fill="{GLYPH}"/>
  <path d="M 74 32 L 74 44 L 86 44 Z" fill="{BODY}"/>
  <line x1="52" y1="58" x2="78" y2="58" stroke="{BODY}" stroke-width="5" stroke-linecap="round"/>
  <line x1="52" y1="70" x2="78" y2="70" stroke="{BODY}" stroke-width="5" stroke-linecap="round"/>
  <line x1="52" y1="82" x2="70" y2="82" stroke="{BODY}" stroke-width="5" stroke-linecap="round"/>
""",

    "applications-graphics": f"""\
  <!-- Framed picture: sun + mountains -->
  <rect x="34" y="40" width="60" height="48" rx="5" fill="none" stroke="{GLYPH}" stroke-width="7"/>
  <circle cx="51" cy="55" r="6" fill="{GLYPH}"/>
  <path d="M 40 84 L 56 63 L 67 74 L 78 58 L 88 84 Z" fill="{GLYPH}"/>
""",

    "applications-system": f"""\
  <!-- Monitor -->
  <rect x="32" y="36" width="64" height="44" rx="5" fill="{GLYPH}"/>
  <rect x="40" y="44" width="48" height="28" rx="2" fill="{BODY}"/>
  <rect x="56" y="80" width="16" height="9" fill="{GLYPH}"/>
  <rect x="44" y="89" width="40" height="7" rx="3" fill="{GLYPH}"/>
""",

    "applications-utilities": f"""\
  <!-- Open-end wrench -->
  <g transform="rotate(45 64 64)">
    <rect x="58" y="44" width="12" height="44" rx="5" fill="{GLYPH}"/>
    <circle cx="64" cy="44" r="14" fill="{GLYPH}"/>
    <rect x="57" y="27" width="14" height="17" fill="{BODY}"/>
  </g>
""",

    "applications-games": f"""\
  <!-- Gamepad -->
  <rect x="36" y="50" width="56" height="30" rx="15" fill="{GLYPH}"/>
  <rect x="48" y="62.5" width="16" height="5" rx="1" fill="{BODY}"/>
  <rect x="53.5" y="57" width="5" height="16" rx="1" fill="{BODY}"/>
  <circle cx="76" cy="60" r="3.5" fill="{BODY}"/>
  <circle cx="84" cy="68" r="3.5" fill="{BODY}"/>
""",

    "applications-science": f"""\
  <!-- Erlenmeyer flask -->
  <path d="M 56 34 L 56 58 L 38 88 Q 35 95 43 95 L 85 95 Q 93 95 90 88 L 72 58 L 72 34"
        fill="none" stroke="{GLYPH}" stroke-width="7" stroke-linejoin="round"/>
  <line x1="51" y1="34" x2="77" y2="34" stroke="{GLYPH}" stroke-width="8" stroke-linecap="round"/>
  <path d="M 51 76 L 77 76 L 86 88 Q 89 93 83 93 L 45 93 Q 39 93 42 88 Z" fill="{GLYPH}"/>
""",
}

# Extra filenames that render the same art (XFCE's xfsm-* lookup names,
# the hybrid-sleep alias, and the Whisker command-button names).
ALIASES = {
    "xfsm-logout": "system-log-out",
    "xfsm-reboot": "system-reboot",
    "xfsm-shutdown": "system-shutdown",
    "xfsm-suspend": "system-suspend",
    "xfsm-hibernate": "system-hibernate",
    "xfsm-switch-user": "system-switch-user",
    "system-suspend-hibernate": "system-suspend",
    "xfsm-lock": "system-lock-screen",
    "preferences-system": "preferences-desktop",
    "org.xfce.settings.manager": "preferences-desktop",
    "xfce4-settings-manager": "preferences-desktop",
    # XFCE's "Accessories" menu uses xfce-accessories.directory
    # (Icon=applications-accessories), NOT the freedesktop Utility name, so
    # it needs the same wrench/tools badge as applications-utilities.
    "applications-accessories": "applications-utilities",
}


def svg_for(glyph: str) -> str:
    return (
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" '
        'viewBox="0 0 128 128">\n'
        f"{DISC}{glyph}</svg>\n"
    )


def write_svgs() -> list[str]:
    ACTIONS.mkdir(parents=True, exist_ok=True)
    for name, glyph in GLYPHS.items():
        (ACTIONS / f"{name}.svg").write_text(svg_for(glyph))
    return list(GLYPHS)


def render_pngs(names: list[str]) -> None:
    for name in names:
        svg = ACTIONS / f"{name}.svg"
        for size in SIZES:
            out_dir = ICONS_OUT / f"{size}x{size}" / "actions"
            out_dir.mkdir(parents=True, exist_ok=True)
            out = out_dir / f"{name}.png"
            subprocess.run(
                [
                    "inkscape",
                    str(svg),
                    "--export-type=png",
                    f"--export-filename={out}",
                    f"--export-width={size}",
                    f"--export-height={size}",
                ],
                check=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            )
            print(f"  rendered {name} @ {size}")


def write_aliases() -> None:
    for alias, src in ALIASES.items():
        for size in SIZES:
            d = ICONS_OUT / f"{size}x{size}" / "actions"
            src_png = d / f"{src}.png"
            if src_png.exists():
                shutil.copy2(src_png, d / f"{alias}.png")
        print(f"  alias {alias} -> {src}")


def main() -> None:
    svg_only = "--svg-only" in sys.argv
    names = write_svgs()
    print(f"Wrote {len(names)} SVGs into {ACTIONS}")
    if svg_only:
        return
    render_pngs(names)
    write_aliases()
    subprocess.run(
        ["gtk-update-icon-cache", "-f", str(ICONS_OUT)],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )
    print("\nDone. Reload: xfdesktop --reload & xfce4-panel -r")


if __name__ == "__main__":
    main()
