#!/usr/bin/env python3
import cgi, sys
sys.path.insert(0, '/opt/ngon/apps')
from managers.auth_manager import AuthManager, generate_login_page_html

_form = cgi.FieldStorage()
_auth = AuthManager('how_to_site_issues')
_auth_required, _should_exit, _headers = _auth.require_auth(_form)

if _should_exit:
    print("Content-Type: application/json")
    if _headers:
        print(_headers)
    print("")
    if _auth_required:
        print('{"success": false, "error": "Authentication required"}')
    else:
        print('{"success": true}')
    sys.exit(0)

if _auth_required:
    print("Content-Type: text/html")
    print("")
    print(generate_login_page_html("How-To: Site Issues"))
    sys.exit(0)


sys.path.insert(0, '/var/www/html/ngon')
from links import generate_dropdown_html, generate_dropdown_css, generate_dropdown_js
_user_access = AuthManager.get_user_access()
_nav_html = generate_dropdown_html(_user_access)
_nav_css = generate_dropdown_css()
_nav_js = generate_dropdown_js()

print("Content-Type: text/html\n")

HTML = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NGON How-To: Site Issues</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link rel="stylesheet" href="/status/styles.css?v=30" />
<style>__NAV_CSS__</style>
<style>
html, body { background: #1a1a1a !important; }
body { padding-bottom: 60px; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb { background: #666; border-radius: 3px; }

.header {
    background-color: rgba(255,255,255,0.05) !important;
    border-radius: 8px !important;
    padding: 30px !important;
    margin: 20px !important;
    border: 1px solid rgba(255,255,255,0.1) !important;
    border-bottom: none !important;
    display: flex !important;
    justify-content: space-between !important;
    align-items: flex-start !important;
}
.header h1.dropdown-title {
    font-size: 2.2em !important;
    font-weight: 600 !important;
    margin: 3px 0 0 0 !important;
    line-height: 1.2 !important;
}

.howto-body { max-width: 900px; margin: 0 auto; padding: 20px; }

h2 { font-size: 22px; color: #00ff00; margin: 40px 0 14px 0; padding-bottom: 8px; border-bottom: 1px solid #333; }
h3 { font-size: 17px; color: #4a9eff; margin: 24px 0 10px 0; }
p { margin: 10px 0; color: #ccc; }
ul, ol { margin: 10px 0 10px 24px; color: #ccc; }
li { margin: 6px 0; }
code { background: #2a2a2a; padding: 2px 6px; border-radius: 3px; font-family: 'Menlo','Consolas',monospace; font-size: 13px; color: #ffaa00; }

.toc { background: #222; border: 1px solid #333; border-radius: 6px; padding: 16px 20px; margin: 20px 0; }
.toc h3 { color: #e0e0e0; margin-top: 0; font-size: 14px; text-transform: uppercase; letter-spacing: 1px; }
.toc ul { list-style: none; margin: 10px 0 0 0; }
.toc li { margin: 4px 0; }
.toc a { color: #4a9eff; text-decoration: none; }
.toc a:hover { color: #00ff00; }

.cheat { background: #1e2a1e; border: 1px solid #2a4a2a; border-radius: 6px; padding: 18px 22px; margin: 20px 0; }
.cheat h3 { color: #00ff00; margin-top: 0; }
.cheat table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 14px; }
.cheat th, .cheat td { padding: 8px 10px; text-align: left; border-bottom: 1px solid #2a4a2a; vertical-align: top; }
.cheat th { color: #00ff00; font-weight: 600; }
.cheat td { color: #ccc; }

.callout { border-left: 3px solid #4a9eff; background: #1e232a; padding: 12px 16px; margin: 16px 0; border-radius: 0 4px 4px 0; }
.callout.warn { border-left-color: #ff6600; background: #2a1f12; }
.callout.good { border-left-color: #00ff00; background: #122a12; }
.callout .label { font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; display: block; margin-bottom: 4px; }
.callout.warn .label { color: #ff6600; }
.callout.good .label { color: #00ff00; }
.callout p { margin: 4px 0; }

.swatch { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.s-green { background: #00ff00; }
.s-red   { background: #ff4444; }
.s-yellow{ background: #ffdd00; }
.s-grey  { background: #888888; }

.example { background: #161616; border: 1px solid #333; border-radius: 6px; padding: 14px 18px; margin: 16px 0; font-family: 'Menlo','Consolas',monospace; font-size: 13px; color: #ddd; white-space: pre-wrap; line-height: 1.6; }
.example .site { color: #cfe3cf; font-weight: 600; }
.example .cnt { color: #ffb454; }
.example .sub { color: #9fb0a0; }

@media (max-width: 700px) {
    .howto-body { padding: 14px; }
    h2 { font-size: 19px; }
    h3 { font-size: 15px; }
    .cheat table { font-size: 12px; }
    .cheat th, .cheat td { padding: 6px 4px; }
}
</style>
</head>
<body>

<div class="header">
    <div>
      <div class="dropdown">
        <h1 class="dropdown-title">NGON Mining - How-To: Site Issues</h1>
        <div class="dropdown-content">__DROPDOWN_HTML__</div>
      </div>
    </div>
</div>

<div class="howto-body">

<p>The <strong>Site Issues</strong> panel sits in the summary column of the Status
Page (where "Miner Control" used to be). It answers one question: <strong>"where
should I go, and what's wrong there?"</strong> Instead of piecing that together
from a stream of individual alerts, it condenses everything the system knows into
a short, per-site list of what's actually broken and worth a look. The old alerts
still fire and are the historical record — this is the at-a-glance triage view on
top of them.</p>

<div class="toc">
    <h3>Contents</h3>
    <ul>
        <li><a href="#read">How to Read It</a></li>
        <li><a href="#cats">The Four Categories</a></li>
        <li><a href="#rules">What Trips Each Flag (the thresholds)</a></li>
        <li><a href="#quiet">What Stays Quiet on Purpose</a></li>
        <li><a href="#sitemap">It Matches the Sitemap</a></li>
        <li><a href="#faq">"Why isn't X showing?" — quick answers</a></li>
    </ul>
</div>

<!-- ============================================================ -->
<h2 id="read">How to Read It</h2>
<p>Collapsed, it's one line per site with a count — the glance. Sites with nothing
wrong show <span style="color:#7fbf7f">✓ clear</span>. Expand a site to see its
<strong>categories</strong>, expand a category to see the specific pods or gens,
and expand those to see the exact problem lines. It refreshes on its own about
every 5 minutes.</p>

<div class="example"><span class="site">GN</span>  <span class="cnt">5</span>
  ▾ Pods Down (2)
      GN 4  · 479 miners dark · since 08-04 20:40
      GN 5  · 480 miners dark
  ▾ Miner Issues (31 miners)
      Stout 1 · <span class="sub">31 miners low hashrate — underperforming, 13 overheating</span>
<span class="site">Will</span> <span class="cnt">2</span>   Butz <span class="cnt">1</span>   ✓ Dan, Ellyson, John, Nate
muted: Osprey — being relocated</div>

<p>Everything expandable is native — no risk in clicking around. The counts and the
site order just help you spot the worst site fastest; there's no "severity score,"
because a field guy reading it knows better than a formula whether 1 pod down beats
10 miners underperforming.</p>

<!-- ============================================================ -->
<h2 id="cats">The Four Categories</h2>
<div class="cheat">
<table>
<tr><th>Category</th><th>What it means</th></tr>
<tr><td><strong>Pods Down</strong></td>
    <td>A whole pod is offline (lost power or network). It <strong>sweeps up its
    group's gen faults</strong> into the same incident — because the gens and the
    pod share a generator group, one outage shows as one entry instead of a dozen
    separate gen alarms. If an <em>entire site</em> goes dark it collapses further
    to a single "Whole site down" line.</td></tr>
<tr><td><strong>Gens Down</strong></td>
    <td>How many generators are down — just the count. The <em>why</em> (the fault
    code, when it tripped) is already on the Status Page, so this stays a number.
    Gens you've disabled or tagged for maintenance are not counted.</td></tr>
<tr><td><strong>Gen Issues</strong></td>
    <td>Running gens throwing a warning worth attention, grouped by gen group with
    each gen listed once and all its issues under it. Also includes
    <strong>bridge down</strong> — a gen that should be streaming live data but its
    wifi bridge went quiet.</td></tr>
<tr><td><strong>Miner Issues</strong></td>
    <td>Miner-level trouble, per pod, matched one-to-one with the sitemap's colors:
    <span class="swatch s-white" style="background:#666"></span><strong>offline</strong>,
    <span class="swatch s-red"></span><strong>zero-hash</strong>, and
    <span class="swatch s-yellow"></span><strong>low-hash / underperforming</strong>.</td></tr>
</table>
</div>

<!-- ============================================================ -->
<h2 id="rules">What Trips Each Flag (the thresholds)</h2>
<p>These are the actual criteria the panel uses. They're intentionally loose — the
goal is a short list you'll trust, not every little thing.</p>

<div class="cheat">
<table>
<tr><th>Flag</th><th>Fires when…</th></tr>
<tr><td>Miners <strong>offline</strong></td>
    <td>More than <strong>25</strong> offline on an online pod. A ~24-port network
    switch dropping looks exactly like this; the couple-always-dead miners in every
    pod don't reach it. So an offline cluster usually means <em>a switch or breaker</em>.</td></tr>
<tr><td>Miners <strong>zero-hash</strong></td>
    <td><strong>5+</strong> miners online but producing nothing (dead but still
    responding).</td></tr>
<tr><td>Miners <strong>low-hash</strong></td>
    <td><strong>5+</strong> miners running below <strong>150 TH/s</strong>
    (underperforming — the sitemap paints these yellow). The
    <strong>"X overheating"</strong> note says how many of them have a heat code
    (vs. degraded hashboards or a stuck power limit).</td></tr>
<tr><td>Gen <strong>coolant</strong></td>
    <td>A gen's coolant hits <strong>215°F+</strong> — above the normal summer
    running band and closing on the <strong>220°F shutdown</strong> (the alarm is
    210°F). Below that, the auto load-shed handles the climb, so we stay quiet.</td></tr>
<tr><td>Gen <strong>bridge down</strong></td>
    <td>A gen that pushed live telemetry within the last few days has gone quiet
    for over 15 minutes — its wifi bridge dropped, so we've lost live data on it.</td></tr>
<tr><td>Gen <strong>warnings</strong></td>
    <td>Live oil / voltage / NG-pressure / other alarms on a running gen (heat and
    the chronic ones handled separately — see below).</td></tr>
<tr><td><strong>Peplink / Starlink</strong></td>
    <td>A site or group's router is offline, or it's fallen back to cell data.</td></tr>
</table>
</div>

<!-- ============================================================ -->
<h2 id="quiet">What Stays Quiet on Purpose</h2>
<p>Half the value is what it <em>doesn't</em> show. These are the deliberate
silences — the operator knowledge baked in so the list stays short and trustworthy.</p>

<div class="cheat">
<table>
<tr><th>Rule</th><th>Why</th></tr>
<tr><td><strong>2-minute confirm</strong> (debounce)</td>
    <td>An issue has to stick around about 2 minutes before it appears, and it
    clears the instant it's gone. A 6-second network blip never shows up; a real
    problem shows on the next refresh. <em>This is why a brand-new issue can take a
    few minutes to appear.</em></td></tr>
<tr><td><strong>Disabled / maintenance gens</strong></td>
    <td>If you've disabled a gen, or tagged it Swap / Inspect / Parts / OOS, it's
    "already handled" — it won't nag you about a gen you're already dealing with.</td></tr>
<tr><td><strong>Group attribution</strong></td>
    <td>When a pod loses power, the gens in its group throwing faults get folded
    into that one outage instead of listed as separate problems.</td></tr>
<tr><td><strong>Chronic gen warnings</strong></td>
    <td>Some warnings (MSC link, ECU malfunction, EGT sensor faults) fire constantly
    fleet-wide and aren't actionable — muted so they don't drown out real ones.</td></tr>
<tr><td><strong>Warm-but-full miners</strong></td>
    <td>A miner with a heat code that's still hashing at full rate isn't costing
    anything (it's green on the sitemap), so it isn't flagged. We only care about
    heat when it's <em>actually</em> reducing hashrate.</td></tr>
<tr><td><strong>Non-operational sites</strong></td>
    <td>Out of Service, Spares, and TBD sites are inventory buckets, not live ops —
    hidden entirely.</td></tr>
<tr><td><strong>Muted sites</strong></td>
    <td>Known exceptions get parked at the bottom with a reason (e.g. a site being
    relocated), so a situation you already know about doesn't clutter the list.</td></tr>
</table>
</div>

<!-- ============================================================ -->
<h2 id="sitemap">It Matches the Sitemap</h2>
<p>The three miner flags use the same lines the <strong>sitemap</strong> uses to
color a square, so whatever the panel names, you can go find it on the sitemap by
color:</p>
<ul>
<li><span class="swatch s-white" style="background:#666"></span><strong>offline</strong>
    → dark squares.</li>
<li><span class="swatch s-red"></span><strong>zero-hash</strong> → the zero-hash
    color.</li>
<li><span class="swatch s-yellow"></span><strong>low-hash / underperforming</strong>
    → yellow squares (anything under 150 TH/s).</li>
</ul>
<p>So "Stout 1: 31 low-hash" means you'll find 31 yellow squares in Stout 1 on the
sitemap — the panel tells you where to go, the sitemap shows you which machines.</p>

<div class="callout good">
<span class="label">It doesn't replace alerts</span>
<p>The alert feeds still fire and remain the full history. Site Issues is the
short, deduplicated "where to go" lens on top — use it to decide where to head,
then use the Status Page and sitemap for the detail.</p>
</div>

<!-- ============================================================ -->
<h2 id="faq">"Why isn't X showing?" — quick answers</h2>
<ul>
<li><strong>Something just broke but it's not listed.</strong> Give it a few
minutes — the 2-minute confirm holds a new issue back until it's proven real (not a
flap), and the panel only refreshes every ~5 min.</li>
<li><strong>A gen I disabled for service isn't listed.</strong> Correct — disabled
and maintenance-tagged gens are treated as already handled.</li>
<li><strong>The status page shows a peplink blip but the panel doesn't.</strong>
Also correct — a brief flap won't survive the 2-minute confirm.</li>
<li><strong>Miners look hot on a machine but the pod isn't flagged.</strong> If
they're still hashing at full rate, that's just summer warmth, not a problem. It
only flags when the heat is dragging hashrate down.</li>
<li><strong>A pod has a few dead miners but no line.</strong> Offline needs 25+
(the switch signature); zero/low-hash need 5+. A handful of dead ones is normal
background.</li>
</ul>

<div class="callout">
<span class="label">Where to go next</span>
<p>Read <strong>How-To: Using the Status Page</strong> for the dashboard the panel
lives on, and <strong>How-To: Power Management</strong> for the AS/AW/EMS toggles
behind a lot of the sleep/wake behavior.</p>
</div>

</div>

<script>__DROPDOWN_JS__</script>
</body>
</html>
"""

HTML = HTML.replace("__NAV_CSS__", _nav_css)
HTML = HTML.replace("__DROPDOWN_CSS__", "")
HTML = HTML.replace("__DROPDOWN_HTML__", _nav_html)
HTML = HTML.replace("__DROPDOWN_JS__", _nav_js)

print(HTML)
