"""Externes Owner-Dashboard für Jami-Dating (Mitglieder + Klicks)."""

from __future__ import annotations

import json
import secrets
from pathlib import Path

from jam.jami_domain import resolve_site_url

ROOT = Path(__file__).resolve().parent.parent
SECRETS = ROOT / "data" / "jami-secrets.local.json"
DASHBOARD_DIR = ROOT / "data" / "jami-dashboard"
DASHBOARD_HTML = DASHBOARD_DIR / "index.html"
DESKTOP_HTML = Path.home() / "Desktop" / "Jami-Owner-Dashboard.html"

DEFAULT_API = "https://www.jami-dating.de"


def ensure_admin_secret() -> str:
    data: dict = {}
    if SECRETS.is_file():
        try:
            data = json.loads(SECRETS.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            data = {}
    key = "jami_admin_secret"
    secret = str(data.get(key, "")).strip()
    if not secret or "HIER" in secret:
        secret = secrets.token_urlsafe(24)
        data[key] = secret
        SECRETS.parent.mkdir(parents=True, exist_ok=True)
        SECRETS.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    return secret


def api_base() -> str:
    return (resolve_site_url() or DEFAULT_API).rstrip("/")


def dashboard_html(*, api_url: str | None = None) -> str:
    base = (api_url or api_base()).rstrip("/")
    return f"""<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>Jami Owner Dashboard</title>
  <style>
    :root {{
      --bg:#0a0610; --card:rgba(255,255,255,0.07); --border:rgba(255,255,255,0.12);
      --text:#fff9fc; --muted:#c4b0d4; --accent:#ff4d8d; --mint:#6ee7d7;
    }}
    * {{ box-sizing:border-box; }}
    body {{
      margin:0; font-family:system-ui,-apple-system,Segoe UI,sans-serif;
      background:var(--bg); color:var(--text);
      background-image:radial-gradient(ellipse 70% 40% at 20% 0%, rgba(255,77,141,0.25), transparent);
      min-height:100vh; padding:1rem;
    }}
    .wrap {{ max-width:960px; margin:0 auto; }}
    h1 {{ margin:0 0 0.25rem; font-size:1.5rem; }}
    .sub {{ color:var(--muted); margin:0 0 1.25rem; font-size:0.92rem; }}
    .login, .grid, .chart, .err {{ display:none; }}
    .login.active, .grid.active, .chart.active {{ display:block; }}
    .err.active {{ display:block; background:rgba(255,80,80,0.15); border:1px solid rgba(255,80,80,0.4);
      padding:0.75rem 1rem; border-radius:12px; margin-bottom:1rem; }}
    .login {{
      background:var(--card); border:1px solid var(--border); border-radius:16px;
      padding:1.25rem; max-width:420px;
    }}
    label {{ display:block; font-size:0.85rem; color:var(--muted); margin-bottom:0.35rem; }}
    input {{
      width:100%; padding:0.75rem 1rem; border-radius:12px; border:1px solid var(--border);
      background:rgba(0,0,0,0.25); color:var(--text); font-size:16px; margin-bottom:0.85rem;
    }}
    button {{
      padding:0.75rem 1.1rem; border:none; border-radius:12px; font-weight:700; cursor:pointer;
      background:linear-gradient(135deg,#ff7a6b,#ff4d7a); color:#fff;
    }}
    .grid {{
      display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:0.85rem;
      margin-bottom:1.25rem;
    }}
    .card {{
      background:var(--card); border:1px solid var(--border); border-radius:16px; padding:1rem 1.1rem;
    }}
    .card .label {{ font-size:0.78rem; color:var(--muted); text-transform:uppercase; letter-spacing:0.04em; }}
    .card .value {{ font-size:2rem; font-weight:800; margin-top:0.35rem; line-height:1; }}
    .card .hint {{ font-size:0.78rem; color:var(--muted); margin-top:0.35rem; }}
    .card.highlight .value {{ color:var(--mint); }}
    .chart {{
      background:var(--card); border:1px solid var(--border); border-radius:16px; padding:1rem 1.1rem 1.25rem;
    }}
    .chart h2 {{ margin:0 0 1rem; font-size:1rem; }}
    .bars {{ display:flex; align-items:flex-end; gap:0.45rem; height:160px; }}
    .bar-col {{ flex:1; display:flex; flex-direction:column; align-items:center; gap:0.35rem; min-width:0; }}
    .bar {{
      width:100%; max-width:42px; border-radius:8px 8px 4px 4px;
      background:linear-gradient(180deg,var(--accent),#b84dff); min-height:4px;
    }}
    .bar-label {{ font-size:0.62rem; color:var(--muted); text-align:center; }}
    .bar-num {{ font-size:0.72rem; color:var(--text); }}
    .toolbar {{ display:flex; flex-wrap:wrap; gap:0.5rem; align-items:center; margin-bottom:1rem; }}
    .toolbar button.secondary {{ background:rgba(255,255,255,0.08); color:var(--text); border:1px solid var(--border); }}
    .updated {{ font-size:0.78rem; color:var(--muted); margin-left:auto; }}
    .section {{
      background:var(--card); border:1px solid var(--border); border-radius:16px;
      padding:1rem 1.1rem 1.25rem; margin-bottom:1.25rem;
    }}
    .section h2 {{ margin:0 0 0.85rem; font-size:1rem; }}
    .gender-row {{
      display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:0.75rem;
      margin-bottom:0.5rem;
    }}
    .gender-card {{
      background:rgba(0,0,0,0.22); border:1px solid var(--border); border-radius:14px; padding:0.85rem 1rem;
    }}
    .gender-card .label {{ font-size:0.78rem; color:var(--muted); }}
    .gender-card .value {{ font-size:1.75rem; font-weight:800; margin-top:0.25rem; }}
    .gender-card.frauen .value {{ color:#ff8ec7; }}
    .gender-card.maenner .value {{ color:#82b1ff; }}
    .gender-card.divers .value {{ color:var(--mint); }}
    .meta-line {{ font-size:0.78rem; color:var(--muted); margin:0 0 0.75rem; }}
    table.traffic {{ width:100%; border-collapse:collapse; font-size:0.85rem; }}
    table.traffic th, table.traffic td {{
      text-align:left; padding:0.45rem 0.35rem; border-bottom:1px solid var(--border);
    }}
    table.traffic th {{ color:var(--muted); font-size:0.72rem; text-transform:uppercase; letter-spacing:0.04em; }}
    table.traffic td.num {{ text-align:right; font-variant-numeric:tabular-nums; }}
    .empty {{ color:var(--muted); font-size:0.85rem; margin:0; }}
  </style>
</head>
<body>
  <div class="wrap">
    <h1>Jami Owner Dashboard</h1>
    <p class="sub">Mitglieder, Geschlecht, Klicks &amp; Traffic-Quellen · extern · nur für dich</p>
    <div id="err" class="err"></div>
    <div id="login" class="login active">
      <label for="adminKey">Admin-Schlüssel</label>
      <input id="adminKey" type="password" autocomplete="current-password" placeholder="aus data/jami-secrets.local.json"/>
      <button type="button" id="btnLogin">Dashboard öffnen</button>
    </div>
    <div id="panel" style="display:none">
      <div class="toolbar">
        <button type="button" id="btnRefresh">Aktualisieren</button>
        <button type="button" class="secondary" id="btnLogout">Abmelden</button>
        <span class="updated" id="updatedAt"></span>
      </div>
      <div class="grid active" id="statsGrid"></div>
      <div class="section">
        <h2>Mitglieder nach Geschlecht</h2>
        <p class="meta-line" id="genderMeta"></p>
        <div class="gender-row" id="genderRow"></div>
      </div>
      <div class="section">
        <h2>Traffic-Quellen (7 Tage)</h2>
        <p class="meta-line">utm_source, Referrer oder „direct“ – ab jetzt mitgezählt</p>
        <div id="trafficWeek"></div>
      </div>
      <div class="section">
        <h2>Anmeldungen nach Quelle (7 Tage)</h2>
        <div id="signupSources"></div>
      </div>
      <div class="chart active">
        <h2>Letzte 7 Tage – Seitenaufrufe</h2>
        <div class="bars" id="chartBars"></div>
      </div>
    </div>
  </div>
  <script>
    const API = {json.dumps(base)};
    const KEY_STORAGE = 'jami_admin_key_v1';
    const errEl = document.getElementById('err');
    const loginEl = document.getElementById('login');
    const panelEl = document.getElementById('panel');
    const keyInput = document.getElementById('adminKey');

    function showErr(msg) {{
      errEl.textContent = msg;
      errEl.classList.add('active');
    }}
    function clearErr() {{ errEl.classList.remove('active'); errEl.textContent = ''; }}

    async function fetchStats(key) {{
      const r = await fetch(API + '/api/admin/dashboard', {{
        headers: {{ 'X-Jami-Admin': key }}
      }});
      const j = await r.json().catch(() => ({{}}));
      if (!r.ok) throw new Error(j.error || ('HTTP ' + r.status));
      return j;
    }}

    function fmt(n) {{ return Number(n || 0).toLocaleString('de-DE'); }}

    function renderGender(g) {{
      const all = g?.all || {{}};
      const today = g?.today || {{}};
      const week = g?.week || {{}};
      document.getElementById('genderMeta').textContent =
        'Heute neu: ' + fmt(today.frauen) + ' Frauen · ' + fmt(today.maenner) + ' Männer · ' + fmt(today.divers) + ' divers · Woche: ' + fmt(week.total) + ' gesamt';
      document.getElementById('genderRow').innerHTML = [
        ['Frauen', all.frauen, 'frauen'],
        ['Männer', all.maenner, 'maenner'],
        ['Divers', all.divers, 'divers'],
      ].map(function(row) {{
        return '<div class="gender-card ' + row[2] + '"><div class="label">' + row[0] + '</div><div class="value">' + fmt(row[1]) + '</div></div>';
      }}).join('');
    }}

    function renderTrafficTable(elId, rows, cols) {{
      const el = document.getElementById(elId);
      if (!rows || !rows.length) {{
        el.innerHTML = '<p class="empty">Noch keine Daten – kommt mit neuen Besuchern/Anmeldungen.</p>';
        return;
      }}
      let html = '<table class="traffic"><thead><tr>';
      cols.forEach(function(c) {{ html += '<th' + (c.num ? ' style="text-align:right"' : '') + '>' + c.label + '</th>'; }});
      html += '</tr></thead><tbody>';
      rows.forEach(function(r) {{
        html += '<tr>';
        cols.forEach(function(c) {{
          const v = typeof c.key === 'function' ? c.key(r) : r[c.key];
          html += '<td' + (c.num ? ' class="num"' : '') + '>' + (c.num ? fmt(v) : String(v || '–')) + '</td>';
        }});
        html += '</tr>';
      }});
      html += '</tbody></table>';
      el.innerHTML = html;
    }}

    function renderStats(d) {{
      const cards = [
        ['Mitglieder', d.members, 'registriert (echt)', true],
        ['Gerade online', d.online, 'letzte ' + (d.onlineWindowMinutes || 5) + ' Min.', false],
        ['Frauen', d.gender?.all?.frauen ?? 0, 'Mitglieder gesamt', true],
        ['Männer', d.gender?.all?.maenner ?? 0, 'Mitglieder gesamt', true],
        ['Aufrufe heute', d.pageViews?.today ?? 0, 'Seitenbesuche', false],
        ['Aufrufe Woche', d.pageViews?.week ?? 0, '7 Tage', false],
        ['Klicks Registrieren', d.registerClicks?.today ?? 0, 'heute', false],
        ['Neue heute', d.registrations?.today ?? 0, 'Registrierungen', true],
        ['Registrierungen gesamt', d.registrations?.total ?? 0, 'seit Start Tracking', false],
      ];
      document.getElementById('statsGrid').innerHTML = cards.map(function(c) {{
        return '<div class="card' + (c[3] ? ' highlight' : '') + '">' +
          '<div class="label">' + c[0] + '</div>' +
          '<div class="value">' + fmt(c[1]) + '</div>' +
          '<div class="hint">' + c[2] + '</div></div>';
      }}).join('');
      renderGender(d.gender || {{}});
      renderTrafficTable('trafficWeek', d.trafficSourcesWeek || [], [
        {{ label: 'Quelle', key: 'source' }},
        {{ label: 'Aufrufe', key: 'pageViews', num: true }},
        {{ label: 'Reg.-Klicks', key: 'registerClicks', num: true }},
        {{ label: 'Anmeldungen', key: 'registrations', num: true }},
      ]);
      renderTrafficTable('signupSources', d.signupSourcesWeek || [], [
        {{ label: 'Quelle bei Anmeldung', key: 'source' }},
        {{ label: 'Neue Profile', key: 'registrations', num: true }},
      ]);
      const days = d.last7Days || [];
      const max = Math.max(1, ...days.map(function(x) {{ return x.pageViews || 0; }}));
      document.getElementById('chartBars').innerHTML = days.map(function(row) {{
        const h = Math.round(((row.pageViews || 0) / max) * 130);
        const label = (row.day || '').slice(5);
        return '<div class="bar-col"><div class="bar-num">' + (row.pageViews || 0) + '</div>' +
          '<div class="bar" style="height:' + h + 'px"></div>' +
          '<div class="bar-label">' + label + '</div></div>';
      }}).join('');
      document.getElementById('updatedAt').textContent = 'Stand: ' + (d.updatedAt || '').replace('T', ' ').slice(0, 19);
    }}

    async function loadDashboard() {{
      clearErr();
      const key = (keyInput.value || localStorage.getItem(KEY_STORAGE) || '').trim();
      if (!key) {{ showErr('Bitte Admin-Schlüssel eingeben.'); return; }}
      try {{
        const data = await fetchStats(key);
        localStorage.setItem(KEY_STORAGE, key);
        loginEl.classList.remove('active');
        panelEl.style.display = 'block';
        renderStats(data);
      }} catch (e) {{
        showErr(e.message || String(e));
      }}
    }}

    document.getElementById('btnLogin').addEventListener('click', loadDashboard);
    document.getElementById('btnRefresh').addEventListener('click', loadDashboard);
    document.getElementById('btnLogout').addEventListener('click', function() {{
      localStorage.removeItem(KEY_STORAGE);
      keyInput.value = '';
      panelEl.style.display = 'none';
      loginEl.classList.add('active');
    }});
    keyInput.addEventListener('keydown', function(e) {{ if (e.key === 'Enter') loadDashboard(); }});
    if (localStorage.getItem(KEY_STORAGE)) {{
      keyInput.value = localStorage.getItem(KEY_STORAGE);
      loadDashboard();
    }}
    setInterval(loadDashboard, 60000);
  </script>
</body>
</html>"""


def write_dashboard_files(*, api_url: str | None = None) -> tuple[Path, Path]:
    html = dashboard_html(api_url=api_url)
    DASHBOARD_DIR.mkdir(parents=True, exist_ok=True)
    DASHBOARD_HTML.write_text(html, encoding="utf-8")
    DESKTOP_HTML.write_text(html, encoding="utf-8")
    return DASHBOARD_HTML, DESKTOP_HTML


def write_setup_note(secret: str) -> Path:
    note = ROOT / "data" / "JAMI_DASHBOARD.txt"
    note.write_text(
        f"""JAMI OWNER DASHBOARD
=====================

Dashboard öffnen:
  python scripts/jami_dashboard.py

Oder Datei im Browser:
  Desktop\\Jami-Owner-Dashboard.html

Admin-Schlüssel (geheim halten):
  {secret}

Steht in: data/jami-secrets.local.json → jami_admin_secret

Nach Deploy muss der Schlüssel in Cloudflare sein (passiert automatisch beim Deploy).

API: {api_base()}/api/admin/dashboard
""",
        encoding="utf-8",
    )
    return note
