#!/usr/bin/env python3
"""Local first-boot wizard: enter customer business name (optional if Factory already claimed).

Listens on :8787 until Flippie submits the form. Prefers claim-by-token when the box
already registered as unclaimed; otherwise register-appliance.
"""
from __future__ import annotations

import json
import os
import socket
import ssl
import urllib.request
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from urllib.parse import parse_qs

ATLAS_URL = os.environ.get("ATLAS_URL", "https://atlas-server.taile9cc75.ts.net").rstrip("/")


def atlas_base() -> str:
    try:
        from atlas_reach import atlas_base as _reach

        return _reach()
    except Exception:
        return ATLAS_URL


FIELD_KIT_KEY = os.environ.get("FIELD_KIT_KEY", "").strip()
ENROLL_TOKEN = os.environ.get("ENROLL_TOKEN", "").strip()
STATE_DIR = Path("/etc/atlas-cyber-protect")
CUSTOMER_JSON = STATE_DIR / "customer.json"
DONE_FLAG = STATE_DIR / "customer-setup.done"
PORT = int(os.environ.get("ACP_SETUP_PORT", "8787"))


def lan_ip() -> str:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("1.1.1.1", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception:
        return ""


def post_claim_or_register(business: str, site: str, email: str) -> dict:
    """Prefer claim-by-token when already registered unclaimed; else full register."""
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    if ENROLL_TOKEN:
        payload = {
            "enroll_token": ENROLL_TOKEN,
            "business_name": business,
            "site_name": site or "Main LAN",
            "notify_email": email,
        }
        url = f"{atlas_base()}/api/cyber-protect/claim-by-token"
    else:
        payload = {
            "field_kit_key": FIELD_KIT_KEY,
            "business_name": business,
            "site_name": site or "Main LAN",
            "hostname": socket.gethostname(),
            "lan_ip": lan_ip(),
            "notify_email": email,
        }
        url = f"{atlas_base()}/api/cyber-protect/register-appliance"
    data = json.dumps(payload).encode()
    req = urllib.request.Request(
        url,
        data=data,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=60, context=ctx) as resp:
        return json.loads(resp.read().decode("utf-8", errors="replace") or "{}")


PAGE = """<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Atlas Cyber Protect — Customer setup</title>
<style>
body{font-family:system-ui,sans-serif;background:#071018;color:#e8f4f2;margin:0;padding:24px}
.card{max-width:480px;margin:40px auto;background:#0d2230;border:1px solid #1e3a4a;border-radius:16px;padding:24px}
h1{margin:0 0 8px;font-size:1.4rem} .muted{color:#8aa8b0;font-size:14px;line-height:1.45}
label{display:block;margin:14px 0 4px;font-size:12px;color:#8aa8b0;text-transform:uppercase;letter-spacing:.06em}
input{width:100%;padding:12px;border-radius:10px;border:1px solid #1e3a4a;background:#07141c;color:#e8f4f2;font:inherit;box-sizing:border-box}
button{margin-top:18px;width:100%;padding:14px;border:0;border-radius:12px;font-weight:700;font-size:15px;
background:linear-gradient(135deg,#1f8f63,#3ecf8e);color:#042016;cursor:pointer}
.err{color:#ff6b7a;margin-top:10px}
.ok{color:#3ecf8e}
</style></head><body>
<div class="card">
  <h1>Name this customer</h1>
  <p class="muted">Enter the <strong>customer business name</strong> so Atlas Factory Guard shows this box under that company — not a shared USB kit name.</p>
  <form method="POST" action="/">
    <label>Customer business name *</label>
    <input name="business_name" required maxlength="120" placeholder="e.g. Acme Hardware (Pty) Ltd" autofocus>
    <label>Site / branch (optional)</label>
    <input name="site_name" maxlength="80" placeholder="e.g. Main shop · Cape Town">
    <label>Notify email (optional)</label>
    <input name="notify_email" type="email" maxlength="120" placeholder="owner@customer.co.za">
    <button type="submit">Save &amp; register on Atlas</button>
  </form>
  {msg}
</div>
</body></html>
"""


class Handler(BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):  # quieter
        print(f"setup: {args[0] if args else fmt}", flush=True)

    def do_GET(self):
        if DONE_FLAG.is_file():
            body = PAGE.replace(
                "{msg}",
                '<p class="ok">Already registered. You can close this page.</p>',
            ).replace("<form", '<form style="display:none"')
        else:
            body = PAGE.replace("{msg}", "")
        self._html(200, body)

    def do_POST(self):
        length = int(self.headers.get("Content-Length") or 0)
        raw = self.rfile.read(length).decode("utf-8", errors="replace")
        form = parse_qs(raw)
        business = (form.get("business_name") or [""])[0].strip()
        site = (form.get("site_name") or [""])[0].strip()
        email = (form.get("notify_email") or [""])[0].strip()
        if len(business) < 2:
            self._html(400, PAGE.replace("{msg}", '<p class="err">Business name is required.</p>'))
            return
        if not FIELD_KIT_KEY and not ENROLL_TOKEN:
            self._html(
                500,
                PAGE.replace(
                    "{msg}",
                    '<p class="err">FIELD_KIT_KEY / ENROLL_TOKEN missing. Rebuild USB from Factory Guard.</p>',
                ),
            )
            return
        try:
            result = post_claim_or_register(business, site, email)
        except Exception as exc:
            self._html(
                502,
                PAGE.replace("{msg}", f'<p class="err">Could not reach Atlas: {exc}</p>'),
            )
            return
        STATE_DIR.mkdir(parents=True, exist_ok=True)
        CUSTOMER_JSON.write_text(json.dumps(result, indent=2), encoding="utf-8")
        token = result.get("enroll_token") or ENROLL_TOKEN or ""
        env_path = STATE_DIR / "acp.env"
        lines = [
            f"ATLAS_URL={ATLAS_URL}",
            f"ENROLL_TOKEN={token}",
            f"FIELD_KIT_KEY={FIELD_KIT_KEY}",
            "ACP_INTERVAL_SEC=45",
            f"BUSINESS_NAME={business}",
            f"SITE_NAME={site or 'Main LAN'}",
            "",
        ]
        env_path.write_text("\n".join(lines), encoding="utf-8")
        env_path.chmod(0o600)
        DONE_FLAG.write_text(result.get("portal_label") or business, encoding="utf-8")
        label = result.get("portal_label") or business
        try:
            import subprocess

            subprocess.run(
                ["systemctl", "restart", "atlas-cyber-protect.service"],
                check=False,
                timeout=30,
            )
            # Do NOT stop the setup service: it runs the customer portal
            # (portal_server.py on :8787), which must stay up after naming.
        except Exception:
            pass
        self._html(
            200,
            PAGE.replace(
                "{msg}",
                f'<p class="ok">Saved as <strong>{label}</strong> on Atlas Factory Guard. '
                "You can close this page.</p>",
            ).replace("<form", '<form style="display:none"'),
        )

    def _html(self, code: int, body: str):
        data = body.encode()
        self.send_response(code)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(data)))
        self.end_headers()
        self.wfile.write(data)


def main() -> None:
    if DONE_FLAG.is_file() and CUSTOMER_JSON.is_file():
        print("Customer already set up — exit", flush=True)
        return
    if not FIELD_KIT_KEY:
        print("WARNING: FIELD_KIT_KEY empty", flush=True)
    ip = lan_ip() or "0.0.0.0"
    print(f"Open http://{ip}:{PORT}/  — enter customer business name", flush=True)
    # Also write MOTD hint
    try:
        Path("/etc/motd").write_text(
            f"\n=== Atlas Cyber Protect ===\n"
            f"Set customer business name:  http://{ip}:{PORT}/\n"
            f"Or: sudo atlas-cyber-protect-setup\n\n",
            encoding="utf-8",
        )
    except Exception:
        pass
    HTTPServer(("0.0.0.0", PORT), Handler).serve_forever()


if __name__ == "__main__":
    main()
