#!/usr/bin/env python3
"""Agent for monitoring and managing Microsoft Defender for Cloud security posture."""

import subprocess
import json
import argparse
from datetime import datetime


def run_az_command(args_list):
    """Execute an Azure CLI command and return parsed JSON output."""
    cmd = ["az"] + args_list + ["--output", "json"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
        if result.returncode != 0:
            print(f"  [-] Error: {result.stderr.strip()}")
            return None
        return json.loads(result.stdout) if result.stdout.strip() else None
    except (subprocess.TimeoutExpired, json.JSONDecodeError) as e:
        print(f"  [-] Command failed: {e}")
        return None


def get_defender_plans():
    """List all Defender for Cloud pricing plans and their status."""
    print("[*] Checking Defender for Cloud plan status...")
    plans = run_az_command(["security", "pricing", "list"])
    if not plans:
        return []
    enabled = []
    for plan in plans:
        tier = plan.get("pricingTier", "Free")
        name = plan.get("name", "Unknown")
        sub_plan = plan.get("subPlan", "")
        status = "ENABLED" if tier == "Standard" else "FREE"
        indicator = "[+]" if tier == "Standard" else "[-]"
        sub_info = f" ({sub_plan})" if sub_plan else ""
        print(f"  {indicator} {name}: {status}{sub_info}")
        if tier == "Standard":
            enabled.append({"name": name, "tier": tier, "subPlan": sub_plan})
    print(f"[*] {len(enabled)} plans enabled out of {len(plans)} total")
    return enabled


def get_secure_score():
    """Retrieve the current Secure Score across subscriptions."""
    print("\n[*] Fetching Secure Score...")
    scores = run_az_command(["security", "secure-score", "list"])
    if not scores:
        return {}
    for score in scores:
        current = score.get("current", 0)
        maximum = score.get("max", 0)
        pct = round((current / maximum * 100), 1) if maximum > 0 else 0
        print(f"  Score: {current}/{maximum} ({pct}%)")
    return scores


def get_security_assessments(severity_filter=None):
    """List security assessments and their health status."""
    print("\n[*] Fetching security assessments...")
    assessments = run_az_command(["security", "assessment", "list"])
    if not assessments:
        return []
    unhealthy = []
    for a in assessments:
        props = a.get("properties", {})
        status = props.get("status", {}).get("code", "")
        if status == "Unhealthy":
            sev = props.get("metadata", {}).get("severity", "Unknown")
            display = props.get("displayName", "Unknown")
            if severity_filter and sev.lower() != severity_filter.lower():
                continue
            unhealthy.append({"name": display, "severity": sev, "status": status})
            print(f"  [{sev.upper()}] {display}")
    print(f"[*] {len(unhealthy)} unhealthy assessments found")
    return unhealthy


def get_security_alerts(days=7):
    """Retrieve recent security alerts from Defender for Cloud."""
    print(f"\n[*] Fetching security alerts (last {days} days)...")
    alerts = run_az_command(["security", "alert", "list"])
    if not alerts:
        return []
    severity_counts = {"High": 0, "Medium": 0, "Low": 0, "Informational": 0}
    active_alerts = []
    for alert in alerts:
        props = alert.get("properties", {})
        status = props.get("status", "")
        if status in ("Active", "InProgress"):
            sev = props.get("severity", "Unknown")
            severity_counts[sev] = severity_counts.get(sev, 0) + 1
            active_alerts.append({
                "name": props.get("alertDisplayName", "Unknown"),
                "severity": sev,
                "status": status,
                "timestamp": props.get("timeGeneratedUtc", ""),
            })
    for sev, count in severity_counts.items():
        if count > 0:
            print(f"  [{sev}] {count} alerts")
    return active_alerts


def check_security_contacts():
    """Verify security contact configuration for alert notifications."""
    print("\n[*] Checking security contact configuration...")
    contacts = run_az_command(["security", "contact", "list"])
    if not contacts:
        print("  [!] No security contacts configured")
        return False
    for contact in contacts:
        email = contact.get("email", "Not set")
        alerts = contact.get("alertNotifications", "off")
        print(f"  Email: {email} | Alert notifications: {alerts}")
    return True


def check_auto_provisioning():
    """Check auto-provisioning settings for security agents."""
    print("\n[*] Checking auto-provisioning settings...")
    settings = run_az_command(["security", "auto-provisioning-setting", "list"])
    if not settings:
        return []
    for s in settings:
        name = s.get("name", "Unknown")
        auto_prov = s.get("autoProvision", "Off")
        indicator = "[+]" if auto_prov == "On" else "[-]"
        print(f"  {indicator} {name}: {auto_prov}")
    return settings


def generate_posture_report(output_path):
    """Generate a comprehensive security posture report."""
    print("[*] Generating security posture report...")
    report = {
        "report_date": datetime.now().isoformat(),
        "defender_plans": get_defender_plans(),
        "secure_score": get_secure_score(),
        "unhealthy_assessments": get_security_assessments(),
        "active_alerts": get_security_alerts(),
        "contacts_configured": check_security_contacts(),
        "auto_provisioning": check_auto_provisioning(),
    }
    with open(output_path, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"\n[*] Report saved to {output_path}")
    return report


def main():
    parser = argparse.ArgumentParser(description="Microsoft Defender for Cloud Security Agent")
    parser.add_argument("action", choices=["plans", "score", "assessments", "alerts",
                                           "contacts", "auto-provision", "full-report"])
    parser.add_argument("--severity", choices=["high", "medium", "low"], help="Filter by severity")
    parser.add_argument("--days", type=int, default=7, help="Alert lookback in days")
    parser.add_argument("-o", "--output", default="defender_report.json")
    args = parser.parse_args()

    if args.action == "plans":
        get_defender_plans()
    elif args.action == "score":
        get_secure_score()
    elif args.action == "assessments":
        get_security_assessments(args.severity)
    elif args.action == "alerts":
        get_security_alerts(args.days)
    elif args.action == "contacts":
        check_security_contacts()
    elif args.action == "auto-provision":
        check_auto_provisioning()
    elif args.action == "full-report":
        generate_posture_report(args.output)


if __name__ == "__main__":
    main()
