#!/usr/bin/env catnip
# Dashboard servi depuis la mémoire, zéro fichier temporaire
# Fetch (httpx) -> transform (Catnip) -> serve (http.server)
#
# DEPS: httpx
# INTERNET: oui (API GitHub)

builtins = import('builtins')
http_server = import('http.server')
webbrowser = import('webbrowser')
math = import('math')
httpx = import('httpx')

# ---------------------------------------------------------------------------
# Handler HTTP -- bridge Python (les lambdas Catnip ne passent pas le
# protocole descripteur, on exec une classe minimale)
# ---------------------------------------------------------------------------

ns = dict()
builtins.exec("""
import http.server
class _H(http.server.BaseHTTPRequestHandler):
    content = b""
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.end_headers()
        self.wfile.write(self.content)
    def log_message(self, *a):
        pass
""", ns)
Handler = ns['_H']

# ---------------------------------------------------------------------------
# Données : fetch repos GitHub via l'API publique
# ---------------------------------------------------------------------------

struct Repo {
    name: str; lang: str; stars: int; description: str
}

resp = httpx.get(
    "https://api.github.com/search/repositories",
    params=dict(q="language:rust stars:>5000", sort="stars", per_page=12),
    headers=dict(Accept="application/vnd.github+json"),
    timeout=10.0,
)
data = resp.json()

# for loop : le broadcasting aplatirait les dicts (itération sur les clés)
repos = list()
for item in data['items'] {
    repos = repos + list(Repo(
            item['full_name'],
            item['language'] ?? "n/a",
            item['stargazers_count'],
            item['description'] ?? "",
        ))
}

# ---------------------------------------------------------------------------
# Spirale de Fibonacci en SVG (broadcasting sur scalaires)
# ---------------------------------------------------------------------------

golden = math.pi * (3 - math.sqrt(5))
n_pts = 200

circles = range(n_pts).[(i: int): str => {
    r = math.sqrt(i) * 8
    theta = i * golden
    cx = 250 + r * math.cos(theta)
    cy = 250 + r * math.sin(theta)
    hue = int((i * 360) / n_pts)
    rad = 3 + i * 0.12
    '<circle cx="' + str(round(cx, 1)) + '" cy="' + str(round(cy, 1)) + '" r="' + str(round(rad, 1)) + '" fill="hsl(' +
        str(hue) +
        ',75%,55%)" opacity=".85"/>'
}]

svg_body = "\n    ".join(circles)

# ---------------------------------------------------------------------------
# HTML -- template .format() (les f-strings ne supportent pas {{ pour les
# accolades CSS, et .format() gère ça nativement)
# ---------------------------------------------------------------------------

row_tpl = '<tr><td><a href="https://github.com/{name}">{name}</a></td><td>{lang}</td><td class="stars">{stars}<span class="bar" style="width:{bar_w}px"></span></td></tr>'

rows = list()
for r in repos {
    rows = rows + list(row_tpl.format(
            name=r.name, lang=r.lang, stars=r.stars, bar_w=int(r.stars / 500),
        ))
}
table_body = "\n        ".join(rows)

CSS = ' * { margin:0; padding:0; box-sizing:border-box }
  body { font-family:system-ui,-apple-system,sans-serif; background:#0d1117; color:#c9d1d9;
         max-width:960px; margin:0 auto; padding:32px 16px }
  h1 { color:#58a6ff; font-size:1.6rem; margin-bottom:4px }
      .sub { color:#8b949e; font-size:.85rem; margin-bottom:24px }
      .tag { display:inline-block; padding:2px 10px; border-radius:12px;
         background:#238636; color:#fff; font-size:11px; vertical-align:middle }
      .grid { display:grid; grid-template-columns:1fr 1fr; gap:24px; align-items:start }
      .card { background:#161b22; border:1px solid #30363d; border-radius:8px; padding:16px; overflow:auto }
      .card h2 { color:#58a6ff; font-size:1rem; margin-bottom:12px }
  table { width:100%; border-collapse:collapse; font-size:.85rem }
  th,td { padding:6px 10px; text-align:left; border-bottom:1px solid #21262d }
  th { color:#8b949e; font-weight:500 }
  a { color:#58a6ff; text-decoration:none }
  a:hover { text-decoration:underline }
      .stars { white-space:nowrap }
      .bar { display:inline-block; height:10px; background:#238636; border-radius:4px;
         vertical-align:middle; margin-left:6px }
  svg { display:block; margin:0 auto }
  @media(max-width:700px) { .grid { grid-template-columns:1fr } }
'

PAGE = '<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8">
<title>Catnip Dashboard</title>
<style>{css}</style></head>
<body>
  <h1>Catnip <span class="tag">live</span></h1>
  <p class="sub">Fetch &rarr; Transform &rarr; Serve. Tout en Catnip.</p>
  <div class="grid">
    <div class="card">
      <h2>Top Rust repos (GitHub API)</h2>
      <table><tr><th>Repo</th><th>Lang</th><th>Stars</th></tr>
        {table}
      </table>
    </div>
    <div class="card" style="text-align:center">
      <h2>Spirale de Fibonacci</h2>
      <p style="color:#8b949e;font-size:.8rem;margin-bottom:8px">{n} points, angle d&#39;or</p>
      <svg width="500" height="500" xmlns="http://www.w3.org/2000/svg"
        style="background:#0d1117;border-radius:12px">
        {svg}
      </svg>
    </div>
  </div>
  <p style="margin-top:20px;color:#484f58;font-size:.75rem;text-align:center">
    Servi depuis la mémoire par http.server.
  </p>
</body></html>'

html = PAGE.format(css=CSS, table=table_body, svg=svg_body, n=n_pts)

# ---------------------------------------------------------------------------
# Serveur one-shot : ouvre le navigateur, sert une requête, puis quitte
# (même pattern que les dashboards hvplot et folium)
# ---------------------------------------------------------------------------

Handler.content = html.encode('utf-8')

server = http_server.HTTPServer(tuple("127.0.0.1", 0), Handler)
port = server.server_address[1]

print(f"⇒ Dashboard : http://127.0.0.1:{port}")

webbrowser.open(f"http://127.0.0.1:{port}")
server.handle_request()
server.server_close()