#!/usr/bin/env python3
"""
Build ncii-shield-ship.zip from ncii-shield-deploy.zip + .env with live keys.

This is a one-off ship artifact for a single cPanel deployment. It takes
the regular deploy zip and adds the operator's .env (containing live API
keys) at the root. The resulting zip is uploaded to cPanel and unzipped
in place — no manual .env creation step on the server.

THREAT MODEL
  - The .env in this build contains live Stripe / Scrape.do / session
    secret keys. The zip must stay on the operator's local machine and
    the cPanel server only.
  - After upload, DELETE the local ncii-shield-ship.zip to limit
    key-bearers to:
      (a) the operator's workstation
      (b) the cPanel server's home directory (and any backups of it).
  - Rotate keys after launch per the rotation policy in .env comments.
"""

import os
import sys
import zipfile
from pathlib import Path

ROOT = Path(r"C:\Users\shafp\Downloads\nic\ncii-shield")
SRC  = ROOT / "ncii-shield-deploy.zip"
DST  = ROOT / "ncii-shield-ship.zip"

ENV_LOCAL = ROOT / ".env"

REQUIRED_KEYS = [
    "STRIPE_SECRET_KEY",
    "STRIPE_PUBLISHABLE_KEY",
    "STRIPE_WEBHOOK_SECRET",
    "SCRAPEDO_API_KEY",
    "APP_URL",
    "PUBLIC_BASE_URL",
    "SESSION_SECRET",
]

def validate_env(text: str) -> list[str]:
    """Return a list of problems with the .env content. Empty list = OK."""
    problems = []
    for k in REQUIRED_KEYS:
        # Find the line, ignore comments.
        found = False
        for line in text.splitlines():
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            if line.startswith(f"{k}="):
                val = line.split("=", 1)[1].strip()
                if not val or val.startswith("your-") or val.endswith("_HERE"):
                    problems.append(f"{k} is empty/placeholder")
                found = True
                break
        if not found:
            problems.append(f"{k} missing")
    return problems

def main():
    if not SRC.exists():
        print(f"missing source zip: {SRC}", file=sys.stderr)
        print("run scripts/build-deploy-zip.py first", file=sys.stderr)
        sys.exit(1)
    if not ENV_LOCAL.exists():
        print(f"missing local .env: {ENV_LOCAL}", file=sys.stderr)
        sys.exit(1)

    env_text = ENV_LOCAL.read_text(encoding="utf-8")
    problems = validate_env(env_text)
    if problems:
        print("WARN: .env has problems:", file=sys.stderr)
        for p in problems:
            print(f"  - {p}", file=sys.stderr)
        # Don't fail hard — operator may want to fill in Resend on the
        # server. But do print clearly.

    if DST.exists():
        DST.unlink()

    # Copy SRC → DST, then append .env at root.
    DST.write_bytes(SRC.read_bytes())

    with zipfile.ZipFile(DST, "a", zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
        # Use a fixed timestamp for reproducibility / simpler diff.
        zi = zipfile.ZipInfo(".env", date_time=(2026, 7, 3, 0, 0, 0))
        zi.compress_type = zipfile.ZIP_DEFLATED
        zf.writestr(zi, env_text)

    size_mb = DST.stat().st_size / (1024 * 1024)
    # Verify the .env entry is inside.
    with zipfile.ZipFile(DST) as zf:
        names = zf.namelist()
        assert ".env" in names, ".env not in final zip"
    print(f"OK -> {DST}  ({size_mb:.2f} MB, {len(names)} files)")
    if problems:
        print("WARN: .env needs attention on the server:", file=sys.stderr)
        for p in problems:
            print(f"  - {p}", file=sys.stderr)

if __name__ == "__main__":
    main()