#!/usr/bin/python3

import os
import re
import sys

# Restricted page keys (see auth_manager.RESTRICTED_PAGES): granted by a
# standalone per-user boolean, NEVER by access:"all". Imported rather than
# re-listed so the nav filter and the page gate can't drift apart. Fails closed:
# if the import breaks, restricted links simply don't render in the nav.
try:
    if '/opt/ngon/apps' not in sys.path:
        sys.path.insert(0, '/opt/ngon/apps')
    from managers.auth_manager import AuthManager as _AuthManager, RESTRICTED_PAGES
except Exception:
    _AuthManager = None
    RESTRICTED_PAGES = set()

# Pages worth having in the nav on a PHONE.
#
# Separate from permissions on purpose. Permissions already filter this menu
# (_has_access below), but they answer "may this person open it", not "is this
# useful on a 6-inch screen" -- and 13 of 15 users currently have access:"all",
# so permissions filter nothing for almost everyone. Using them to declutter a
# phone would mean converting those users to explicit page lists and maintaining
# 13 of them forever, and revoking someone's MARA Report to tidy their phone would
# also remove it from their desktop.
#
# So both filters apply: a link shows on mobile only if the user may see it AND
# it is listed here. Edit this one set to change the mobile menu.
#
# Left out deliberately: the reporting and trend pages (performance, mara_report,
# report_builder, miner_trends, gen_trends, site_uptime, zero_hash, ...) -- those
# are analysis, done sitting down.
MOBILE_PAGE_KEYS = {
    "status_mobile",       # the phone dashboard (/status/m.py)
    "map",                 # where am I / where is the next site
    "cams",                # eyes on a site before driving out
    "bridge_status",       # gen wifi bridges
    "todo",                # the job list
    "nmt",                 # miner tool
    "gen_manager",         # gen notes + status, the field write path
    "mesa_gen_tracker",    # Mesa chat
    "group_text",          # crew comms
    "dead",                # which miners to pull
    "inventory",           # part / miner lookup
    "inventory_management",# put/pull on inventory.ngon.us -- the field write path
    "connex",              # what is stored where
    # The how-to pages. Reference material someone reads standing in front of the
    # thing it describes, which is exactly when they have a phone and not a desk.
    "how_to",              # Power Management: AS, AW, gen disable, EMS
    "how_to_remote_start", # remote gen control
    "how_to_status_page",  # orientation to the dashboard
    "how_to_site_issues",  # what the Site Issues panel flags
    # NOT dataflow: it lives in the Help category but is an animated architecture
    # map, not a how-to, and not something anyone needs in the field.
}

# Pages that have a phone-specific version. On a phone the nav entry swaps to the
# URL here AND is access-checked against the page_key here.
#
# The separate key is the point: "status" and "status_mobile" are different
# grants, so a field tech can be given the phone dashboard without the full
# three-column desktop page. Users with access "all" get both automatically.
MOBILE_PAGES = {
    "status": {"url": "/status/m.py", "page_key": "status_mobile"},
}

# Data structure for all navigation links
# Each entry has a page_key used for access control
LINKS_DATA = {
    "Status & Monitoring": [
        {
            "title": "Status Page",
            "url": "/status/",
            "description": "Real-time status dashboard",
            "page_key": "status"
        },
        {
            "title": "Sites Map",
            "url": "/status/map.py",
            "description": "Interactive map showing all mining sites",
            "page_key": "map"
        },
        {
            "title": "Performance Page",
            "url": "/status/performance.py",
            "description": "Historical hashrate monitoring",
            "page_key": "performance"
        },
        {
            "title": "Cams",
            "url": "/cams/",
            "description": "Blink camera viewer (on-demand fresh snapshots)",
            "page_key": "cams"
        },
        {
            "title": "Wifi Bridge Status",
            "url": "/status/bridge_status.py",
            "description": "Gen wifi bridges: which bridge is on which gen, its IP, and which peplink",
            "page_key": "bridge_status"
        }
    ],
    "Management Tools": [
        {
            "title": "Todo List",
            "url": "/todo/",
            "description": "Shared company todo list",
            "page_key": "todo"
        },
        {
            "title": "NGON Miner Tool (NMT)",
            "url": "/nmm/nmt.py",
            "description": "Comprehensive miner management interface",
            "page_key": "nmt"
        },
        {
            "title": "Generator Manager",
            "url": "/status/gen_manager.py",
            "description": "Generator notes, status, and maintenance tracking",
            "page_key": "gen_manager"
        },
        {
            "title": "Generator Service History",
            "url": "/status/gen_service.py",
            "description": "Service invoice tracking and cost analysis",
            "page_key": "gen_service"
        },
        {
            "title": "Group Text Manager",
            "url": "/status/group_text.py",
            "description": "Shared SMS threads with gas providers, processors and Mesa",
            "page_key": "group_text"
        },
        {
            "title": "Mesa Gen Tracker",
            "url": "/status/mesa_gen_tracker.py",
            "description": "Mesa-facing gen status, run state, and notes",
            "page_key": "mesa_gen_tracker"
        },
        {
            "title": "Dead Miner Hunter",
            "url": "/nmm/dead.py",
            "description": "Find broken miners, build pull lists",
            "page_key": "dead"
        }
    ],
    "Reports & Analytics": [
        {
            "title": "Econs by Site Report Builder",
            "url": "/status/report_builder.py",
            "description": "Build custom cross-source econ reports (hashrate, revenue, gas, service, G&A)",
            "page_key": "report_builder"
        },
        {
            "title": "Site Hashrate & Uptime",
            "url": "/status/site_hashrate_uptime.py",
            "description": "Per-site average hashrate vs spec (utilisation) over 7/30/90 days",
            "page_key": "site_hashrate_uptime"
        },
        {
            "title": "MARA Report",
            "url": "/status/mara_report.py",
            "description": "Comprehensive generator and miner performance reporting",
            "page_key": "mara_report"
        },
        {
            "title": "Zero Hash Analysis",
            "url": "/nmm/zero_hash.py",
            "description": "Analysis tool for zero hashrate miners",
            "page_key": "zero_hash"
        },
        {
            "title": "Miner Trends",
            "url": "/status/miner_trends.py",
            "description": "Historical analysis and performance",
            "page_key": "miner_trends"
        },
        {
            "title": "Generator Trends",
            "url": "/status/gen_trends.py",
            "description": "Historical analysis and performance",
            "page_key": "gen_trends"
        },
        {
            "title": "Gen Outage Report",
            "url": "/gen_outages.py",
            "description": "Repeat-offender gens that initiate group cascades",
            "page_key": "gen_outages"
        },
        {
            "title": "Site Non-Zero Hash based Uptime",
            "url": "/status/site_uptime.py",
            "description": "Historical site uptime analysis based on non-zero hashrate",
            "page_key": "site_uptime"
        },
        {
            "title": "Miner Pod Report",
            "url": "/status/miner_report.py",
            "description": "Hourly mining operation status",
            "page_key": "miner_report"
        },
        {
            "title": "Dead M60 Report",
            "url": "/dead_m60.py",
            "description": "Dead M60 miner analysis and hashboard health",
            "page_key": "dead_m60"
        },
        {
            "title": "Flowmeter Data",
            "url": "/status/flowmeter_data.py",
            "description": "Gas flowmeter daily usage history and live readings per site",
            "page_key": "flowmeter"
        }
    ],
    "Inventory & Assets": [
        {
            "title": "Inventory Management",
            "url": "https://inventory.ngon.us",
            "description": "Put/pull miners and manage inventory (inventory.ngon.us)",
            "page_key": "inventory_management"
        },
        {
            "title": "Inventory Display",
            "url": "/inventory/",
            "description": "Search and filter miners (concept, not complete)",
            "page_key": "inventory"
        },
        {
            "title": "Inventory Comparison",
            "url": "/inventory/inventory_check.py",
            "description": "Compare inventory data with live data from miners",
            "page_key": "inventory_check"
        },
        {
            "title": "Asset Inventory",
            "url": "/connex/",
            "description": "What gear is stored where, by site and container",
            "page_key": "connex"
        },
        {
            "title": "Site Development",
            "url": "https://inventory.ngon.us/site-development/",
            "description": "Plan a site move or a new site build (inventory.ngon.us)",
            "page_key": "site_development",
            # Restricted: a planning tool for a handful of people, so "All Access"
            # does not cover it — it needs an explicit per-user grant in Site
            # Manager, the same way site_manager does.
            "restricted": True
        }
    ],
    "Help": [
        {
            "title": "How-To: Power Management",
            "url": "/status/how_to.py",
            "description": "Field guide to AS, AW, gen disable, and EMS",
            "page_key": "how_to"
        },
        {
            "title": "How-To: Remote Gen Start",
            "url": "/status/how_to_remote_start.py",
            "description": "Remote gen control: manual, clear alarms, start, on-load",
            "page_key": "how_to_remote_start"
        },
        {
            "title": "How-To: Using the Status Page",
            "url": "/status/how_to_status_page.py",
            "description": "New-hire orientation to the status dashboard and its data",
            "page_key": "how_to_status_page"
        },
        {
            "title": "Data Flow Map",
            "url": "/status/dataflow.py",
            "description": "Animated map of how data moves: field, VPN, APIs, stores, pages",
            "page_key": "dataflow"
        },
        {
            "title": "How-To: Site Issues",
            "url": "/status/how_to_site_issues.py",
            "description": "What the Site Issues panel flags, and the rules behind it",
            "page_key": "how_to_site_issues"
        }
    ]
}

# Flat list of all page keys with display names (for site_manager UI)
PAGE_KEYS = []
for _cat, _links in LINKS_DATA.items():
    for _link in _links:
        _entry = {
            "key": _link["page_key"],
            "title": _link["title"],
            "category": _cat
        }
        # Carry "restricted" through so Site Manager renders it as its own
        # amber checkbox instead of a grid box covered by "All Access".
        if _link.get("restricted"):
            _entry["restricted"] = True
        PAGE_KEYS.append(_entry)
# Add pages not in nav but that have access control.
# "restricted" pages are NOT covered by a user's "all" access — they require
# an explicit per-user grant (see auth_manager.RESTRICTED_PAGES).
PAGE_KEYS.append({"key": "site_manager", "title": "Site Manager", "category": "Management Tools", "restricted": True})
PAGE_KEYS.append({"key": "performance_30", "title": "Performance 30-Day", "category": "Reports & Analytics"})
# Generator control capability (Gen Control modal + dynamic group buttons on the
# status page). Not a nav page — an action-gate. Its own Site Manager checkbox so
# field techs can be granted it independently. gen_control_api enforces the same key.
PAGE_KEYS.append({"key": "gen_control", "title": "Gen Control (gen start/manual/clear)", "category": "Management Tools"})
# Research assistant (external, research.ngon.us — read-only Claude reporting agent).
# Not a nav link yet (site not live); registered so Site Manager can grant it to
# limited (non-"all") accounts. "all" users are covered automatically. The gate
# lives on the research box, which checks this key via research_sync_api verify_cookie.
# Mobile status dashboard (/status/m.py). A separate grant from "status" so a
# field tech can have the phone dashboard without the full desktop page.
PAGE_KEYS.append({"key": "status_mobile", "title": "Status Page (mobile)", "category": "Status & Monitoring"})
PAGE_KEYS.append({"key": "research", "title": "Research (research.ngon.us)", "category": "Reports & Analytics"})
# Money (/status/money.py). Link-only page -- deliberately NOT in the nav
# dropdown, but registered so access can be granted/revoked like any other page.
PAGE_KEYS.append({"key": "money", "title": "Money (BTC earnings)", "category": "Reports & Analytics"})


_RESTRICTED_GRANTS = None


def _restricted_grants():
    """Restricted page keys the CURRENT user (per cookie) has been granted.

    Restricted keys live as standalone booleans on the user record, not in the
    access list, so the access value the nav callers hand us can't answer this.
    Resolved from the cookie here instead of changing 36 call sites. Computed
    once per process; every importer of this module is a CGI, so that is once
    per request.
    """
    global _RESTRICTED_GRANTS
    if _RESTRICTED_GRANTS is None:
        grants = set()
        if _AuthManager is not None and RESTRICTED_PAGES:
            try:
                username = _AuthManager.get_current_user()
                if username:
                    record = _AuthManager._load_users().get(username) or {}
                    grants = {k for k in RESTRICTED_PAGES if record.get(k)}
            except Exception:
                grants = set()
        _RESTRICTED_GRANTS = grants
    return _RESTRICTED_GRANTS


def _has_access(page_key, access):
    """Check if access list permits a given page_key"""
    # Restricted pages ignore the access list entirely, including "all".
    if page_key in RESTRICTED_PAGES:
        return page_key in _restricted_grants()
    if access is None or access == "all":
        return True
    if isinstance(access, list):
        return page_key in access
    return False


# Function to generate link cards HTML
def generate_links_html(access=None):
    html_content = ""
    for category, links in LINKS_DATA.items():
        filtered = [l for l in links if _has_access(l["page_key"], access)]
        if not filtered:
            continue
        html_content += f'''
        <div class="links-section">
            <h2>{category}</h2>
            <div class="links-grid">'''

        for link in filtered:
            html_content += f'''
                <a href="{link['url']}" class="link-card" target="_blank">
                    <div class="link-title">{link['title']}</div>
                    <div class="link-description">{link['description']}</div>
                    <div class="link-url">{link['url']}</div>
                </a>'''

        html_content += '''
            </div>
        </div>'''

    return html_content


# Function to generate dropdown HTML for other pages
def _is_mobile_client():
    """True when the request came from a phone, per the CGI User-Agent.

    Sniffing a UA is crude, but the alternative is worse: without it the nav is
    only phone-shaped on the pages that remember to ask for it, so a field guy who
    taps through to the Todo list gets handed the desktop menu -- and the "Status
    Page" link there drops him on the three-column desktop page. The menu should
    follow the device, not the page he happens to be standing on.

    Deliberately narrow: "Mobile" covers iOS and Android browsers, and iPad is
    listed because iPadOS reports a desktop UA in some modes but not all. A false
    negative just means the full menu, which is the current behaviour anyway.
    """
    ua = os.environ.get('HTTP_USER_AGENT', '')
    return bool(re.search(r'Android|iPhone|iPad|iPod|Mobile|Opera Mini|IEMobile', ua, re.I))


def generate_dropdown_html(access=None, mobile=None):
    """Nav dropdown, filtered by what the user may see.

    mobile=None (the default) auto-detects from the User-Agent, so every page
    gets a phone-shaped menu on a phone without each of the 36 callers having to
    opt in. Pass True/False to force it.

    In mobile mode links lose target="_blank" -- on a phone that piles up tabs
    with no obvious way back -- and MOBILE_URLS swaps in any phone-specific page.

    MOBILE_PAGE_KEYS is applied ONLY to users whose access is "all". If someone
    has an explicit page list, a human already decided exactly what they should
    see, and second-guessing that would hide a page you deliberately granted.
    """
    if mobile is None:
        mobile = _is_mobile_client()
    unrestricted = access is None or access == "all"
    dropdown_html = ""
    for category, links in LINKS_DATA.items():
        # Resolve each link to the key/URL that applies on THIS device before
        # access-checking, so a phone checks "status_mobile" while a desktop
        # checks "status".
        resolved = []
        for link in links:
            key, url = link["page_key"], link["url"]
            swap = MOBILE_PAGES.get(key) if mobile else None
            if swap:
                mkey = swap.get("page_key", key)
                if _has_access(mkey, access):
                    key, url = mkey, swap.get("url", url)
                # else fall through to the desktop key/URL: someone granted only
                # "status" still gets the desktop page on their phone rather than
                # a menu with no status link at all. No privilege leak -- it is
                # the page they were granted.
            resolved.append((link, key, url))

        filtered = [(l, k, u) for (l, k, u) in resolved if _has_access(k, access)]
        if mobile and unrestricted:
            filtered = [(l, k, u) for (l, k, u) in filtered if k in MOBILE_PAGE_KEYS]
        if not filtered:
            continue
        dropdown_html += f'<div class="dropdown-section">'
        dropdown_html += f'<div class="dropdown-category">{category}</div>'
        for link, _key, url in filtered:
            target = "" if mobile else ' target="_blank"'
            dropdown_html += f'<a href="{url}" class="dropdown-link"{target}>{link["title"]}</a>'
        dropdown_html += '</div>'
    return dropdown_html


# Function to generate dropdown CSS
def generate_dropdown_css():
    return '''
    /* Universal Navigation Dropdown Styles */
    .dropdown {
        position: relative;
        display: inline-block;
    }

    .dropdown-title {
        cursor: pointer;
        transition: color 0.2s ease;
        user-select: none;
        color: #00ff00;
        font-size: 2.2em;
        font-weight: 600;
        margin: 0;
    }

    .dropdown-title:hover {
        color: #4a9eff;
    }

    .dropdown-content {
        display: none;
        position: absolute;
        background-color: #1a1a1a;
        min-width: 350px;
        box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.4);
        z-index: 1000;
        border: 1px solid #2a2a2a;
        border-radius: 8px;
        padding: 10px 0;
        top: 100%;
        left: 0;
    }

    .dropdown:hover .dropdown-content {
        display: block;
    }

    .dropdown-section {
        padding: 5px 0;
    }

    .dropdown-category {
        color: #00ff00;
        font-weight: bold;
        padding: 8px 15px 5px 15px;
        font-size: 14px;
        border-bottom: 1px solid #2a2a2a;
        margin-bottom: 5px;
    }

    .dropdown-link {
        color: #e0e0e0;
        padding: 6px 25px;
        text-decoration: none;
        display: block;
        transition: background-color 0.2s ease;
        font-size: 13px;
    }

    .dropdown-link:hover {
        background-color: #2a2a2a;
        color: #4a9eff;
        text-decoration: none;
    }

    /* Mobile dropdown handling */
    @media (max-width: 768px) {
        .dropdown-content {
            position: fixed;
            top: 0;
            left: 0;
            right: auto;
            width: 75vw;
            min-width: 0;
            z-index: 2000;
            max-height: 100vh;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            border-radius: 0 0 8px 0;
            border: none;
            border-right: 1px solid #2a2a2a;
            border-bottom: 1px solid #2a2a2a;
        }

        .dropdown:hover .dropdown-content {
            display: none; /* Disable hover on mobile */
        }

        .dropdown-title {
            position: relative;
        }

        /* Add click functionality for mobile */
        .dropdown-content.show {
            display: block !important;
        }
    }

    /* Header styles */
    .header {
        background: #1a1a1a;
        padding: 20px;
        border-bottom: 2px solid #2a2a2a;
    }
    '''

# Function to generate dropdown JavaScript
def generate_dropdown_js():
    return '''
    // Mobile dropdown functionality
    document.addEventListener('DOMContentLoaded', function() {
        const dropdownTitle = document.querySelector('.dropdown-title');
        const dropdownContent = document.querySelector('.dropdown-content');

        if (dropdownTitle && dropdownContent) {
            dropdownTitle.addEventListener('click', function(e) {
                if (window.innerWidth <= 768) {
                    e.preventDefault();
                    dropdownContent.classList.toggle('show');
                }
            });

            // Close dropdown when clicking outside
            document.addEventListener('click', function(e) {
                if (!e.target.closest('.dropdown') && dropdownContent.classList.contains('show')) {
                    dropdownContent.classList.remove('show');
                }
            });

            // Close dropdown when window is resized to desktop
            window.addEventListener('resize', function() {
                if (window.innerWidth > 768) {
                    dropdownContent.classList.remove('show');
                }
            });
        }
    });
    '''

# Function to generate complete header HTML with navigation
def generate_header_html(page_title, additional_controls="", access=None):
    return f'''
    <div class="header">
        <div class="dropdown">
            <h1 class="dropdown-title">NGON Mining - {page_title}</h1>
            <div class="dropdown-content">{generate_dropdown_html(access)}</div>
        </div>
        {additional_controls}
    </div>
    '''

# Links page in the same style as status dashboard
html = '''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NGON Links</title>
    <link rel="stylesheet" href="status/styles.css">
    <style>
        .links-container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }

        .links-section {
            background: #1a1a1a;
            border: 1px solid #2a2a2a;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 20px;
        }

        .links-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 15px;
            margin-top: 15px;
        }

        .link-card {
            background: #2a2a2a;
            border: 1px solid #3a3a3a;
            border-radius: 8px;
            padding: 15px;
            transition: all 0.2s ease;
            display: block;
            text-decoration: none;
            color: #e0e0e0;
        }

        .link-card:hover {
            border-color: #00ff00;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 255, 0, 0.1);
            text-decoration: none;
            color: #fff;
        }

        .link-title {
            color: #00ff00;
            font-weight: 600;
            font-size: 16px;
            margin-bottom: 8px;
        }

        .link-description {
            color: #888;
            font-size: 14px;
            line-height: 1.4;
        }

        .link-url {
            color: #4a9eff;
            font-size: 12px;
            margin-top: 8px;
            font-family: monospace;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>NGON Links</h1>
    </div>

    <div class="links-container">''' + generate_links_html() + '''
    </div>
</body>
</html>'''

if __name__ == "__main__":
    print("Content-Type: text/html\n")
    print(html)
