"""Publish deploy outputs to SSM + format GitHub PR comments (D-050).

Two canonical mechanisms:
  1. SSM Parameter Store (SecureString, KMS-encrypted) for runtime-injectable
     values — resources that need to read outputs at runtime (e.g. an ECS
     task reading its S3 bucket name).
  2. GitHub PR comment / job summary for human-readable outputs (connection
     strings, ALB DNS, S3 bucket URL, CloudFront domain). No raw secrets in
     the comment — only non-sensitive outputs (DNS names, ARNs, bucket names).

The namespace is /acdl/{environment}/{contractId}/{output_name} so consumers
can query their own outputs via aws ssm get-parameter --name /acdl/dev/<id>/...
"""

import json
import os
import sys

try:
    import boto3
except ImportError:
    boto3 = None

SSM_PREFIX = "/acdl"
KMS_KEY_ID_ENV = "ACDL_KMS_KEY_ID"

# Outputs that are safe to display in a PR comment (no secrets).
SAFE_OUTPUT_NAMES = {
    "distribution_domain_name",
    "bucket_arn",
    "bucket_name",
    "bucket_regional_domain_name",
    "web_acl_arn",
    "lb_arn",
    "listener_arn",
    "target_group_arn",
    "service_arn",
    "cluster_arn",
    "repository_url",
    "db_endpoint",
    "db_arn",
    "distribution_arn",
    "vpc_id",
    "subnet_ids",
}


def _ssm_client():
    if boto3 is None:
        raise RuntimeError("boto3 is required for SSM publishing")
    return boto3.client("ssm")


def _kms_key_id():
    """Return the KMS key ID for SSM SecureString encryption.

    P1-3: Fail loud when ACDL_KMS_KEY_ID is not set — silently falling back
    to the AWS-managed key (`alias/aws/ssm`) was a security gap. The platform
    CMK must be explicitly configured. Set ACDL_ALLOW_DEFAULT_KMS=1 to use
    the AWS-managed key as an escape hatch for local testing.
    """
    key_id = os.environ.get(KMS_KEY_ID_ENV)
    if key_id:
        return key_id
    if os.environ.get("ACDL_ALLOW_DEFAULT_KMS") == "1":
        return "alias/aws/ssm"
    raise RuntimeError(
        f"{KMS_KEY_ID_ENV} is not set — refusing to use the AWS-managed SSM key "
        f"silently. Set {KMS_KEY_ID_ENV} to your platform CMK ARN, or set "
        f"ACDL_ALLOW_DEFAULT_KMS=1 to use alias/aws/ssm (escape hatch for local testing)."
    )


def publish_to_ssm(outputs, environment, contract_id):
    """Write each output to SSM Parameter Store as a SecureString.

    Returns a dict of {output_name: parameter_arn} for successful writes.
    Skips None values and empty strings.
    """
    if boto3 is None:
        return {}
    client = _ssm_client()
    kms_key = _kms_key_id()
    results = {}
    for name, value in outputs.items():
        if value is None:
            continue
        if isinstance(value, str) and not value.strip():
            continue
        param_name = f"{SSM_PREFIX}/{environment}/{contract_id}/{name}"
        try:
            client.put_parameter(
                Name=param_name,
                Value=str(value),
                Type="SecureString",
                KeyId=kms_key,
                Overwrite=True,
            )
            results[name] = param_name
        except Exception as e:
            # Don't fail the pipeline if one output fails to publish, but log it
            import sys
            print(f"WARNING: SSM put_parameter failed for {name}: {e}", file=sys.stderr)
            results[name] = None
    return results


def format_comment(outputs, environment, contract_id, ssm_results=None):
    """Format a GitHub PR comment / job summary with human-readable outputs.

    Only non-sensitive outputs (SAFE_OUTPUT_NAMES) are included. Sensitive
    outputs are noted as 'published to SSM' without their values.
    """
    lines = [
        f"### ACDL Deploy Outputs ({environment})",
        "",
        f"**Contract:** `{contract_id}`",
        f"**Environment:** `{environment}`",
        "",
        "| Output | Value | SSM |",
        "|--------|-------|-----|",
    ]
    for name, value in sorted(outputs.items()):
        if value is None:
            continue
        if isinstance(value, str) and not value.strip():
            continue
        safe = name in SAFE_OUTPUT_NAMES
        display = str(value) if safe else "`(published to SSM)`"
        ssm_path = ""
        if ssm_results and ssm_results.get(name):
            ssm_path = f"`{ssm_results[name]}`"
        elif ssm_results is not None:
            ssm_path = "—"
        lines.append(f"| `{name}` | {display} | {ssm_path} |")
    lines.append("")
    lines.append("> Sensitive outputs are available via `aws ssm get-parameter --name /acdl/" + environment + "/" + contract_id + "/<output_name>` (KMS-encrypted SecureString).")
    return "\n".join(lines)


def post_github_comment(comment_text, token=None, repo=None, pr_number=None):
    """Post a comment to a GitHub PR via the GitHub API.

    Uses GITHUB_TOKEN from env if token is None. Uses GITHUB_REPOSITORY if
    repo is None. Uses the PR number from the GITHUB_REF env if pr_number is
    None (extracts from refs/pull/<N>/merge). No-op if not in a PR context.
    """
    if token is None:
        token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
    if repo is None:
        repo = os.environ.get("GITHUB_REPOSITORY", "")
    if pr_number is None:
        ref = os.environ.get("GITHUB_REF", "")
        if "refs/pull/" in ref:
            try:
                pr_number = int(ref.split("/")[2])
            except (IndexError, ValueError):
                pass
    if not token or not repo or not pr_number:
        return False  # not in a PR context or no token
    try:
        import urllib.request
        url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments"
        data = json.dumps({"body": comment_text}).encode()
        req = urllib.request.Request(url, data=data, method="POST")
        req.add_header("Authorization", f"token {token}")
        req.add_header("Accept", "application/vnd.github+json")
        urllib.request.urlopen(req, timeout=10)
        return True
    except Exception as e:
        import sys
        print(f"WARNING: GitHub PR comment failed: {e}", file=sys.stderr)
        return False


if __name__ == "__main__":
    # CLI: output_publisher.py <outputs.json> <environment> <contract_id>
    if len(sys.argv) != 4:
        print("usage: output_publisher.py <outputs.json> <environment> <contract-id>", file=sys.stderr)
        sys.exit(2)
    with open(sys.argv[1]) as f:
        outputs = json.load(f)
    env = sys.argv[2]
    cid = sys.argv[3]
    ssm_results = publish_to_ssm(outputs, env, cid)
    comment = format_comment(outputs, env, cid, ssm_results)
    print(comment)