#!/usr/bin/env python3
"""
Security hardening for FlowTorch production.
- Control consent authorization
- Allowlist checking
- HMAC-signed receipts
- GA-OFF tripwire
"""

import os
import hmac
import json
import subprocess
from hashlib import sha256
from typing import Optional, Dict, Any, Set, Tuple
from datetime import datetime, timezone


# Control consent allowlist (IP addresses or API keys)
# In production: Load from config file or environment
CONTROL_ALLOWLIST: Set[str] = {
    "127.0.0.1",           # Localhost
    "::1",                 # IPv6 localhost
    "192.168.1.0/24",      # Local network (example)
}


def check_ga_nudge_forbid() -> bool:
    """
    Check if GA_NUDGE_FORBID=1 (validation requirement).

    Returns:
        True if GA-OFF mode active, False otherwise

    Raises:
        RuntimeError: If GA_NUDGE_FORBID != 1 (tripwire)
    """
    ga_forbid = os.getenv("GA_NUDGE_FORBID", "0")

    if ga_forbid != "1":
        raise RuntimeError(
            "GA-OFF validation mode required. Set GA_NUDGE_FORBID=1 to proceed. "
            "This prevents numerological golden-ratio constants in production."
        )

    return True


def check_control_consent(
    client_ip: str,
    consent: bool,
    allowlist: Optional[Set[str]] = None
) -> Tuple[bool, Optional[str]]:
    """
    Check if client is authorized for basin control.

    Args:
        client_ip: Client IP address
        consent: Explicit consent flag from request
        allowlist: Custom allowlist (if None, uses global)

    Returns:
        (authorized, error_message) tuple
    """
    if allowlist is None:
        allowlist = CONTROL_ALLOWLIST

    # Require explicit consent
    if not consent:
        return False, "control_consent=true required for basin control"

    # Check allowlist
    if client_ip not in allowlist:
        # Check if IP is in CIDR range (simple check for /24)
        for cidr in allowlist:
            if "/" in cidr:
                network, prefix = cidr.rsplit("/", 1)
                if prefix == "24":
                    # Simple /24 check
                    network_prefix = ".".join(network.split(".")[:-1])
                    ip_prefix = ".".join(client_ip.split(".")[:-1])
                    if network_prefix == ip_prefix:
                        return True, None

        return False, f"Client {client_ip} not in control allowlist"

    return True, None


def create_signed_receipt(
    phi: float,
    R: float,
    MI: float,
    energy_uJ: float,
    cardinality: int,
    state: str,
    delta_base: float,
    phi0_applied: float,
    secret_key: Optional[bytes] = None,
) -> Dict[str, Any]:
    """
    Create HMAC-signed receipt for basin control.

    Args:
        phi: Measured basin phase (degrees)
        R: Locking strength (0-1)
        MI: Mutual information (bits)
        energy_uJ: Energy consumption (microjoules)
        cardinality: Basin count
        state: Target state letter
        delta_base: DELTA_BASE used
        phi0_applied: Applied PHI0
        secret_key: HMAC key (if None, uses env RECEIPT_SECRET)

    Returns:
        Signed receipt dict
    """
    if secret_key is None:
        # Get key from environment (base64-encoded)
        key_b64 = os.getenv("RECEIPT_SECRET")
        if key_b64:
            import base64
            secret_key = base64.b64decode(key_b64)
        else:
            # Generate ephemeral key (WARNING: Not persistent across restarts)
            secret_key = os.urandom(32)

    # Get git commit for provenance
    try:
        git_commit = subprocess.check_output(
            ["git", "rev-parse", "HEAD"],
            cwd=os.path.dirname(__file__),
            stderr=subprocess.DEVNULL,
            text=True
        ).strip()
    except:
        git_commit = None

    # Build receipt
    receipt = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "basin": {
            "phi_deg": phi,
            "R_spectral": R,
            "MI_bits": MI,
        },
        "control": {
            "cardinality": cardinality,
            "state": state,
            "delta_base": delta_base,
            "phi0_applied": phi0_applied,
        },
        "energy": {
            "uJ": energy_uJ,
            "uJ_per_nat": energy_uJ / (MI * 0.693147) if MI > 0 else None,  # Convert bits → nats
        },
        "schema_version": "helix:basin_control:v1",
        "git_commit": git_commit,
    }

    # Sign receipt (HMAC-SHA256)
    receipt_bytes = json.dumps(receipt, sort_keys=True).encode()
    signature = hmac.new(secret_key, receipt_bytes, sha256).hexdigest()

    receipt["signature"] = signature

    return receipt


def verify_receipt(receipt: Dict[str, Any], secret_key: bytes) -> bool:
    """
    Verify HMAC signature on receipt.

    Args:
        receipt: Receipt dict with 'signature' field
        secret_key: HMAC key

    Returns:
        True if signature valid, False otherwise
    """
    if "signature" not in receipt:
        return False

    # Extract signature
    signature = receipt.pop("signature")

    # Recompute signature
    receipt_bytes = json.dumps(receipt, sort_keys=True).encode()
    expected_sig = hmac.new(secret_key, receipt_bytes, sha256).hexdigest()

    # Constant-time comparison
    valid = hmac.compare_digest(signature, expected_sig)

    # Restore signature
    receipt["signature"] = signature

    return valid


# GA-OFF tripwire on module import (fail-fast)
try:
    check_ga_nudge_forbid()
except RuntimeError as e:
    # Allow import to succeed, but log warning
    import warnings
    warnings.warn(str(e))
