#!/usr/bin/env python3
"""
HERO static site builder — FLAT layout, five-area structure (Sept 2026 redesign).
Run:  python3 _src/build.py      (from the hero-site folder)

Pages: Home · About Us · Rainforest · Marine Justice · River to Reef ·
       HERO Hub · Student Hub · Donate · Contact

Output: one .html file per page at the site root, images in /images/,
styles in /assets/, config.js (client-editable content) + site.js
(applies config.js to the pages at load time), sitemap.xml.

Links inside the page sources are written as folder-style paths
("marine-justice/") and mapped to flat filenames here.
"""
import os, re, sys, html, json
sys.path.insert(0, os.path.dirname(__file__))
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

SITE_URL = "https://heroonline.org"   # used for sitemap.xml (production domain)

# folder-style path  ->  flat filename
FILES = {
    "": "index.html",
    "about/": "about.html",
    "rainforest/": "rainforest.html",
    "marine-justice/": "marine-justice.html",
    "river-to-reef/": "river-to-reef.html",
    "hero-hub/": "hero-hub.html",
    "student-hub/": "student-hub.html",
    "donate/": "donate.html",
    "contact/": "contact.html",
}

NAV = [
    ("Home", ""),
    ("About Us", "about/"),
    ("Rainforest", "rainforest/"),
    ("Marine Justice", "marine-justice/"),
    ("River to Reef", "river-to-reef/"),
    ("HERO Hub", "hero-hub/"),
    ("Student Hub", "student-hub/"),
]

# ---------- images ----------
IMAGE_KEYS = {}   # key -> (default path, label), collected for config.js

def pic(key, src, alt, cls="", eager=False):
    """A real photo wrapped in a data-img hook so config.js can swap it."""
    IMAGE_KEYS[key] = (src, alt)
    lazy = '' if eager else ' loading="lazy"'
    return (f'<span class="img {cls}" data-img="{key}" data-alt="{html.escape(alt)}">'
            f'<img src="{src}" alt="{html.escape(alt)}"{lazy}></span>')

PALETTES = {
    "ocean":  ("#0b2a3f", "#1a9aa8"),
    "reef":   ("#137a8a", "#e26d4f"),
    "forest": ("#1f5c3a", "#3f9a63"),
    "sand":   ("#c9b992", "#e9e1d2"),
    "river":  ("#2f7d4f", "#1a9aa8"),
    "dusk":   ("#123a55", "#e26d4f"),
}
_ph_id = [0]

def ph(key, label, palette="ocean", ratio="16/9"):
    """Gradient placeholder for a photo HERO does not have yet; config.js can fill it."""
    IMAGE_KEYS[key] = ("", label)
    a, b = PALETTES.get(palette, PALETTES["ocean"])
    _ph_id[0] += 1
    i = _ph_id[0]
    w, h = (1600, 900) if ratio == "16/9" else (1200, 900)
    svg = (f'<svg viewBox="0 0 {w} {h}" preserveAspectRatio="xMidYMid slice" role="img" aria-label="{html.escape(label)}">'
           f'<defs><linearGradient id="g{i}" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="{a}"/><stop offset="1" stop-color="{b}"/></linearGradient></defs>'
           f'<rect width="{w}" height="{h}" fill="url(#g{i})"/>'
           f'<path d="M0 {h*0.72} Q {w*0.25} {h*0.62} {w*0.5} {h*0.72} T {w} {h*0.72} V {h} H0 Z" fill="rgba(255,255,255,.10)"/>'
           f'<text x="{w*0.05}" y="{h*0.92}" font-family="Inter,system-ui,sans-serif" font-size="{int(h*0.045)}" fill="rgba(255,255,255,.85)">{html.escape(label)}</text></svg>')
    return f'<span class="img" data-img="{key}" data-alt="{html.escape(label)}">{svg}</span>'

def card(title, href, text, img_html, chip=None, more="Learn more"):
    chip_html = f'<span class="chip teal">{chip}</span>' if chip else ''
    return (f'<article class="card"><div class="ph">{img_html}</div>'
            f'<div class="body">{chip_html}<h3><a href="{href}">{title}</a></h3><p>{text}</p>'
            f'<a class="more" href="{href}">{more} →</a></div></article>')

def page_hero(crumb, eyebrow, title, lede, cls="teal", bg=None, bg_key=None, bg_alt="", fit=False):
    """Page banner. With bg=path it is a photo banner (config.js can swap it via bg_key)."""
    if bg:
        IMAGE_KEYS[bg_key] = (bg, bg_alt)
        photo = f'<div class="bg hero-bg has-photo" data-img="{bg_key}" data-alt="{html.escape(bg_alt)}" style="background-image:url({bg})"></div>'
        cls += " photo" + (" fit" if fit else "")
    else:
        photo = ''
    return (f'<div class="page-hero {cls}">{photo}<div class="wrap">'
            f'<div class="crumbs"><a href="{{R}}">Home</a> › {crumb}</div>'
            f'<div class="eyebrow">{eyebrow}</div><h1>{title}</h1><p>{lede}</p></div></div>')

# ---------- page shell ----------
HEAD = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{title}</title>
<meta name="description" content="{desc}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/style.css">
<link rel="icon" href="favicon.ico" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="192x192" href="images/favicon-192x192.png">
<link rel="apple-touch-icon" sizes="180x180" href="images/apple-touch-icon.png">
<meta name="theme-color" content="#0b2a3f">
<script src="config.js"></script>
{extra_head}
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<div class="topbar"><div class="wrap"><span><span data-cfg="org.longName">Hannig Environmental Research Organization</span> · a 501(c)(3) nonprofit</span><span><a href="student-hub/">For students &amp; teachers</a> · <a href="contact/">Contact</a></span></div></div>
<header class="site"><div class="wrap">
  <a class="brand" href="" aria-label="HERO — Hannig Environmental Research Organization, home"><img class="logo" src="images/hero-logo.png" alt="HERO — Hannig Environmental Research Organization" width="768" height="293"></a>
  <button class="menu-btn" aria-expanded="false" aria-controls="mainnav" onclick="var n=document.getElementById('mainnav');n.classList.toggle('open');this.setAttribute('aria-expanded',n.classList.contains('open'))">Menu</button>
  <nav class="main" id="mainnav" aria-label="Main"><ul>{navitems}<li><a class="donate" href="donate/" data-cfg-href="donate.buttonLink">Donate</a></li></ul></nav>
</div></header>
<main id="main">
'''

FOOT = '''
</main>
<div class="support-band"><div class="wrap">
  <p data-cfg-html="donate.supportBand"><strong>It turns out that everyone needs a HERO — even our environment.</strong> Every gift supports research, rainforest protection, marine justice, and free resources for students.</p>
  <a class="btn dark" href="donate/" data-cfg-href="donate.buttonLink">Donate today</a>
</div></div>
<footer class="site"><div class="wrap">
  <div class="cols">
    <div>
      <h4 data-cfg="org.shortName">HERO</h4>
      <p data-cfg="org.mission">HERO was established to support and promote global research, education, and the protection of our life-sustaining planet. From river to reef and classroom to courtroom, we strive to be a HERO for the environment.</p>
      <p class="small">HERO is recognized by the IRS (Tax ID <span data-cfg="org.ein">92-1108128</span>) as a 501(c)(3) non-profit tax-exempt charity and by the State of California. Donations are deductible as allowed by law. Consult your tax advisor.</p>
    </div>
    <div>
      <h4>Our work</h4>
      <ul><li><a href="rainforest/">Rainforest Preservation &amp; Research</a></li><li><a href="marine-justice/">Marine Justice</a></li><li><a href="river-to-reef/">River to Reef</a></li><li><a href="hero-hub/">HERO Hub</a></li><li><a href="student-hub/">Student Hub</a></li></ul>
    </div>
    <div>
      <h4>Organization</h4>
      <ul><li><a href="about/">About Us</a></li><li><a href="about/#board">Board &amp; Advisory Board</a></li><li><a href="about/#community">HERO Community</a></li><li><a href="donate/">Donate</a></li><li><a href="contact/">Contact</a></li></ul>
    </div>
    <div>
      <h4>Stay connected</h4>
      <p class="small"><a href="contact/"><strong>Send us a message →</strong></a><br>Email: <a data-cfg-mailto="org.email" href="mailto:info@heroonline.org">info@heroonline.org</a><br><span data-cfg="org.address"></span></p>
      <p class="small" id="social-links"></p>
      <p class="small">Sister effort: <a href="https://hannigcupglobal.org/" rel="noopener">The Hannig Cup</a> — the charity regatta that started it all.</p>
    </div>
  </div>
  <div class="legal"><span>© 2026 <span data-cfg="org.longName">Hannig Environmental Research Organization</span>. All rights reserved. · <a href="about/#privacy">Privacy</a> · <a href="about/#terms">Terms</a></span><span class="credit">Website by <a href="https://blackrockwebdesign.com" rel="noopener" target="_blank">Blackrockwebdesign.com</a></span></div>
</div></footer>
<script src="assets/site.js"></script>
</body>
</html>
'''

def flatten_links(s):
    """Rewrite folder-style hrefs to flat filenames."""
    def repl(m):
        href = m.group(1)
        if href.startswith(("http", "mailto", "#")):
            return m.group(0)
        path, _, frag = href.partition("#")
        if path in FILES:
            return f'href="{FILES[path]}{"#" + frag if frag else ""}"'
        return m.group(0)
    return re.sub(r'href="([^"]*)"', repl, s)

def build_page(page):
    path = page["path"]
    fname = FILES[path]
    navitems = ""
    for label, href in NAV:
        cur = ' aria-current="page"' if (path == href if href == "" else path.startswith(href)) else ""
        navitems += f'<li><a href="{href}"{cur}>{label}</a></li>'
    body = page["body"].replace("{R}", "")
    out = HEAD.format(title=html.escape(page["title"]), desc=html.escape(page.get("desc", "")),
                      navitems=navitems, extra_head=page.get("head", "")) + body + FOOT
    out = flatten_links(out)
    with open(os.path.join(ROOT, fname), "w") as f:
        f.write(out)
    return fname

def write_config():
    """Generate config.js ONLY if it does not exist yet, so client edits survive rebuilds.
    (Delete config.js and rebuild to regenerate defaults.)"""
    import content as C
    import build as B
    target = os.path.join(ROOT, "config.js")
    if os.path.exists(target):
        print("config.js exists — left untouched")
        return
    img_lines = "\n".join(f'    "{k}": {json.dumps(v[0])},   // {v[1]}' for k, v in sorted(B.IMAGE_KEYS.items()))
    J = lambda x: json.dumps(x, indent=4, ensure_ascii=False)
    cfg = f'''// =====================================================================
//  HERO website — config.js
//  Everything in this file can be edited by hand. Save, then reload the
//  page. No build step needed. Keep the commas and quotes as they are.
//  A missing comma breaks the whole file — the pages then show their
//  built-in defaults, so nothing goes blank.
// =====================================================================
window.HERO_CONFIG = {{

  // ---------- Organization details (header, footer, About) ----------
  org: {{
    shortName: "HERO",
    longName: "Hannig Environmental Research Organization",
    tagline: "Focused on marine and rain forest ecology and environmental justice for our fragile marine environment.",
    mission: "HERO was established to support and promote global research, education, and the protection of our life-sustaining planet. From river to reef and classroom to courtroom, we strive to be a HERO for the environment.",
    email: "info@heroonline.org",
    address: "",                       // e.g. "PO Box 123, Redwood City, CA 94063" (shown in the footer when filled in)
    ein: "92-1108128",
    social: {{                          // leave blank to hide
      facebook: "",
      instagram: "",
      youtube: "",
      linkedin: ""
    }}
  }},

  // ---------- Donate ----------
  donate: {{
    buttonLink: "donate.html",         // change to a PayPal / Zeffy / Stripe URL to send donors straight there
    supportBand: "<strong>It turns out that everyone needs a HERO — even our environment.</strong> Every gift supports research, rainforest protection, marine justice, and free resources for students.",
    embedHtml: "",                     // paste a donation-form embed code here (shows on donate.html)
    checksPayableTo: "Hannig Environmental Research Organization"
  }},

  // ---------- Links ----------
  links: {{
    riverToReefVideo: "https://fb.watch/GvGy328nVl/"   // "Watch the video" button on the River to Reef page
  }},

  // ---------- Homepage ----------
  home: {{
    slideTagline: "Focused on marine and rain forest ecology and environmental justice for our fragile marine environment.",
    missionHeading: "The H.E.R.O. Mission",
    quote: "After almost 100 years on the planet, I now understand the most important place on Earth is not on land, but at sea.",
    quoteBy: "Sir David Attenborough"
  }},

  // ---------- Images ----------
  // Every picture on the site, by name. To change one: put the new file in
  // /images/ and type its path here. Blank = a colored placeholder.
  images: {{
{img_lines}
  }},

  // ---------- Partners / HERO Community (name, website, logo) ----------
  partners: {J(C.PARTNERS)},

  // ---------- HERO Hub: news & articles (newest first) ----------
  // kind: "article" (opens the url) or "video" (embeds the url — a YouTube
  // or Vimeo *embed* address). image: a thumbnail in /images/hub/ (optional).
  hub: {J(C.HUB)},

  // ---------- Rainforest page: reports from our scientists ----------
  // Add one entry per report: {{ title, author, date, url }} — url can be a PDF in /images/docs/
  reports: {J(C.REPORTS)},

  // ---------- River to Reef page: articles from Dr. Daniel Medina ----------
  articles: {J(C.ARTICLES)},

  // ---------- River to Reef page: water temperature & conditions ----------
  // One card per reading: {{ label, value, note }}
  waterData: {J(C.WATER_DATA)},

  // ---------- Student Hub: student submissions ----------
  // kind: "video" (Vimeo/YouTube embed url) or "article" (link)
  students: {J(C.STUDENTS)},

  // ---------- Student Hub: educational resources ----------
  resources: {J(C.RESOURCES)},

  // ---------- Donate page: thank you to our donors ----------
  donors: {J(C.DONORS)}
}};
'''
    with open(target, "w") as f:
        f.write(cfg)
    print("wrote config.js")

def write_sitemap(pages):
    import datetime
    today = datetime.date.today().isoformat()
    urls = []
    for p in pages:
        fname = FILES[p["path"]]
        loc = SITE_URL + "/" + ("" if fname == "index.html" else fname)
        pri = "1.0" if fname == "index.html" else "0.8"
        urls.append(f"  <url><loc>{loc}</loc><lastmod>{today}</lastmod><priority>{pri}</priority></url>")
    with open(os.path.join(ROOT, "sitemap.xml"), "w") as f:
        f.write('<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + "\n".join(urls) + "\n</urlset>\n")
    print("wrote sitemap.xml")

def main():
    import pages_home, pages_about, pages_areas, pages_hubs, pages_donate, pages_contact
    pages = []
    for m in (pages_home, pages_about, pages_areas, pages_hubs, pages_donate, pages_contact):
        pages += m.PAGES
    for p in pages:
        print("wrote", build_page(p))
    write_config()
    write_sitemap(pages)

if __name__ == "__main__":
    main()
