#!/usr/bin/env python3
"""Agent for auditing Terraform infrastructure for security misconfigurations."""

import json
import argparse
import subprocess
from datetime import datetime


def run_checkov(terraform_dir, output_format="json"):
    """Run Checkov static analysis on Terraform code."""
    cmd = ["checkov", "-d", terraform_dir, "--framework", "terraform", "--output", output_format, "--compact"]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    if output_format == "json":
        try:
            return json.loads(result.stdout)
        except json.JSONDecodeError:
            return {"raw_output": result.stdout, "error": result.stderr}
    return result.stdout


def run_checkov_on_plan(plan_json_path):
    """Run Checkov on a Terraform plan JSON file for accurate analysis."""
    cmd = ["checkov", "-f", plan_json_path, "--framework", "terraform_plan", "--output", "json"]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        return {"raw_output": result.stdout}


def run_tfsec(terraform_dir, min_severity="HIGH"):
    """Run tfsec Terraform security scanner."""
    cmd = ["tfsec", terraform_dir, "--format", "json", "--minimum-severity", min_severity]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        return {"raw_output": result.stdout}


def parse_checkov_results(checkov_output):
    """Parse Checkov output and extract failed checks with details."""
    findings = []
    if isinstance(checkov_output, list):
        checks = checkov_output
    elif isinstance(checkov_output, dict):
        checks = checkov_output.get("results", {}).get("failed_checks", [])
    else:
        return findings
    for check in checks:
        if isinstance(check, dict):
            findings.append({
                "check_id": check.get("check_id", ""),
                "check_name": check.get("check_result", {}).get("check", {}).get("name", check.get("name", "")),
                "resource": check.get("resource", ""),
                "file": check.get("file_path", ""),
                "line": check.get("file_line_range", []),
                "severity": check.get("severity", "UNKNOWN"),
                "guideline": check.get("guideline", ""),
            })
    return findings


def parse_tfsec_results(tfsec_output):
    """Parse tfsec output and extract findings."""
    findings = []
    results = tfsec_output.get("results", [])
    if results is None:
        return findings
    for r in results:
        findings.append({
            "rule_id": r.get("rule_id", ""),
            "description": r.get("description", ""),
            "severity": r.get("severity", ""),
            "resource": r.get("resource", ""),
            "location": f"{r.get('location', {}).get('filename', '')}:{r.get('location', {}).get('start_line', '')}",
            "resolution": r.get("resolution", ""),
        })
    return findings


def scan_tf_plan_for_issues(plan_json_path):
    """Directly scan a Terraform plan JSON for common security issues."""
    with open(plan_json_path) as f:
        plan = json.load(f)
    issues = []
    for change in plan.get("resource_changes", []):
        after = change.get("change", {}).get("after", {})
        resource_type = change.get("type", "")
        address = change.get("address", "")
        if resource_type == "aws_s3_bucket":
            if not after.get("server_side_encryption_configuration"):
                issues.append({"resource": address, "issue": "S3 bucket without encryption", "severity": "HIGH"})
        if resource_type == "aws_security_group_rule":
            for cidr in after.get("cidr_blocks", []):
                if cidr == "0.0.0.0/0" and after.get("from_port", 0) <= 22 <= after.get("to_port", 0):
                    issues.append({"resource": address, "issue": "SSH open to 0.0.0.0/0", "severity": "CRITICAL"})
        if resource_type == "aws_iam_policy":
            policy_doc = after.get("policy", "{}")
            if isinstance(policy_doc, str):
                try:
                    doc = json.loads(policy_doc)
                    for stmt in doc.get("Statement", []):
                        if stmt.get("Action") == "*" and stmt.get("Effect") == "Allow":
                            issues.append({"resource": address, "issue": "IAM wildcard actions", "severity": "CRITICAL"})
                except json.JSONDecodeError:
                    pass
    return issues


def generate_report(checkov_findings, tfsec_findings, plan_issues):
    """Generate combined audit report."""
    all_findings = []
    for f in checkov_findings:
        f["source"] = "checkov"
        all_findings.append(f)
    for f in tfsec_findings:
        f["source"] = "tfsec"
        all_findings.append(f)
    for f in plan_issues:
        f["source"] = "plan_scan"
        all_findings.append(f)
    severity_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
    all_findings.sort(key=lambda x: severity_order.get(x.get("severity", "LOW"), 4))
    return {
        "audit_date": datetime.utcnow().isoformat(),
        "total_findings": len(all_findings),
        "critical": sum(1 for f in all_findings if f.get("severity") == "CRITICAL"),
        "high": sum(1 for f in all_findings if f.get("severity") == "HIGH"),
        "findings": all_findings,
    }


def main():
    parser = argparse.ArgumentParser(description="Terraform Security Audit Agent")
    parser.add_argument("--terraform-dir", help="Directory with Terraform code")
    parser.add_argument("--plan-json", help="Terraform plan JSON file")
    parser.add_argument("--output", default="terraform_audit.json")
    parser.add_argument("--tool", choices=["checkov", "tfsec", "both", "plan_only"], default="both")
    args = parser.parse_args()

    checkov_findings = []
    tfsec_findings = []
    plan_issues = []

    if args.terraform_dir:
        if args.tool in ("checkov", "both"):
            print("[+] Running Checkov...")
            raw = run_checkov(args.terraform_dir)
            checkov_findings = parse_checkov_results(raw)
            print(f"    Found {len(checkov_findings)} issues")
        if args.tool in ("tfsec", "both"):
            print("[+] Running tfsec...")
            raw = run_tfsec(args.terraform_dir)
            tfsec_findings = parse_tfsec_results(raw)
            print(f"    Found {len(tfsec_findings)} issues")

    if args.plan_json:
        print("[+] Scanning Terraform plan...")
        plan_issues = scan_tf_plan_for_issues(args.plan_json)
        print(f"    Found {len(plan_issues)} issues")

    report = generate_report(checkov_findings, tfsec_findings, plan_issues)
    with open(args.output, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"[+] {report['critical']} critical, {report['high']} high out of {report['total_findings']} total")
    print(f"[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
