#!/usr/bin/python3
"""Shared frontend constants, emitted as JavaScript.

Serves `window.NGON = {...}` so pages and modals stop each carrying their own
copy of the same value. Before this, GAS_CUFT_PER_KWH lived in two files behind
a "keep in sync" comment, excludedSites in 14 places across 8 files, and
genStatuses in three (status page, gen_manager, gen modal).

Deliberately NOT served off status_api / window.statusCore. gen_manager.py loads
status_gen_modal.js WITHOUT status_data.js, which is why those modals carry
`window.statusCore?.x || <hardcoded>` fallbacks -- the fallbacks are load-bearing,
not sloppiness. A source that depends on statusCore existing would leave
gen_manager on hardcoded copies forever. A plain script tag works on any page.

Values come from master_config misc.display when present, else the DEFAULTS
below, which match what the frontend hardcoded at the time of the split. Nothing
needs adding to master_config for this to work; misc.display is the hook for
making them operator-editable later.

This file is included by pages that must render regardless, so every failure
path still emits valid JavaScript -- a broken emit here would break the status
page and gen_manager at once.
"""
import json
import sys

# Frontend values as they were hardcoded pre-consolidation. Changing a default
# here changes it everywhere; prefer setting master_config misc.display instead.
DEFAULTS = {
    # Cubic feet of gas per kWh -- calibration constant for the gas estimates.
    "GAS_CUFT_PER_KWH": 11,
    # Pseudo-sites kept in the data but excluded from operational totals.
    "excludedSites": ["Out of Service", "Spares"],
    # Generator maintenance statuses (NGON status, not the DSE run state).
    "genStatuses": {
        "active":      {"label": "Active",      "color": "#00ff00", "textColor": "black"},
        "active-swap": {"label": "Active-Swap", "color": "#ff6600", "textColor": "white"},
        "swap":        {"label": "Swap",        "color": "#ff6600", "textColor": "white"},
        "inspect":     {"label": "Inspect",     "color": "#ffaa00", "textColor": "black"},
        "parts":       {"label": "Parts",       "color": "#ff4444", "textColor": "white"},
        "gas":         {"label": "Gas",         "color": "#4a9eff", "textColor": "white"},
        "oos":         {"label": "OOS",         "color": "#888888", "textColor": "white"},
    },
}


def _from_config():
    """misc.display overrides, key by key. Never raises.

    Returns (values, source) where source is "config" or "defaults". The source is
    emitted alongside the values on purpose: this function must not break the page,
    so it swallows config errors -- and a silent fallback is indistinguishable from
    a working read whenever the defaults happen to match config, which is exactly
    how the first version of this file shipped calling a ConfigManager method that
    does not exist. Publishing the source makes the fallback observable.
    """
    values = dict(DEFAULTS)
    try:
        sys.path.insert(0, '/opt/ngon/apps')
        from managers.config_manager import config
        # config._master_config is how the rest of the codebase reads the whole
        # config (see notifications_api, generator_monitor). There is no public
        # whole-config accessor; the get_*() methods are all section-specific.
        master = config._master_config or {}
        display = (master.get("misc", {}) or {}).get("display", {}) or {}
        if not display:
            return values, "defaults"
        for key in DEFAULTS:
            if key in display:
                values[key] = display[key]
        return values, "config"
    except Exception as exc:
        sys.stderr.write("constants_cgi: config read failed (%s), serving defaults\n" % exc)
        return values, "defaults"


def main():
    try:
        values, source = _from_config()
        values = dict(values, _source=source)
        body = "window.NGON = %s;\n" % json.dumps(values, indent=2, sort_keys=True)
    except Exception:
        body = "window.NGON = %s;\n" % json.dumps(dict(DEFAULTS, _source="defaults"))
    print("Content-Type: application/javascript")
    print("Cache-Control: no-cache, must-revalidate")
    print("")
    print(body)


main()
