#!/usr/bin/env python3
"""SOC Metrics and KPI Tracking Agent - Collects and reports SOC performance metrics."""

import json
import os
import time
import logging
import argparse
from datetime import datetime

import requests

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

SPLUNK_BASE = os.environ.get("SPLUNK_URL", "https://localhost:8089")
HEADERS = {"Content-Type": "application/json"}


def authenticate_splunk(base_url, username, password):
    """Authenticate to Splunk and return session key."""
    resp = requests.post(
        f"{base_url}/services/auth/login",
        data={"username": username, "password": password},
        verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true",  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        timeout=30,
    )
    resp.raise_for_status()
    session_key = resp.json()["sessionKey"]
    logger.info("Authenticated to Splunk successfully")
    return {"Authorization": f"Splunk {session_key}"}


def run_splunk_search(base_url, headers, query, earliest="-30d", latest="now"):
    """Execute a Splunk search and return results."""
    search_body = {
        "search": f"search {query}",
        "earliest_time": earliest,
        "latest_time": latest,
        "output_mode": "json",
    }
    resp = requests.post(
        f"{base_url}/services/search/jobs",
        headers=headers,
        data=search_body,
        verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true",  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        timeout=30,
    )
    resp.raise_for_status()
    sid = resp.json()["sid"]

    for _ in range(120):
        status = requests.get(
            f"{base_url}/services/search/jobs/{sid}",
            headers=headers,
            params={"output_mode": "json"},
            verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true",  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
            timeout=30,
        ).json()
        if status["entry"][0]["content"]["isDone"]:
            break
        time.sleep(2)

    results = requests.get(
        f"{base_url}/services/search/jobs/{sid}/results",
        headers=headers,
        params={"output_mode": "json", "count": 0},
        verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true",  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        timeout=30,
    ).json()
    return results.get("results", [])


def collect_mttd_metrics(base_url, headers):
    """Collect Mean Time to Detect metrics from Splunk ES notable events."""
    query = (
        'index=notable earliest=-30d status_label="Resolved*" '
        "| eval mttd_seconds = _time - orig_time "
        "| where mttd_seconds > 0 AND mttd_seconds < 86400 "
        "| stats avg(mttd_seconds) AS avg_mttd, median(mttd_seconds) AS med_mttd, "
        "perc90(mttd_seconds) AS p90_mttd by urgency "
        "| eval avg_mttd_min = round(avg_mttd / 60, 1)"
    )
    results = run_splunk_search(base_url, headers, query)
    logger.info("MTTD metrics collected: %d urgency levels", len(results))
    return results


def collect_mttr_metrics(base_url, headers):
    """Collect Mean Time to Respond metrics."""
    query = (
        'index=notable earliest=-30d status_label="Resolved*" '
        "| eval mttr_seconds = status_end - _time "
        "| where mttr_seconds > 0 AND mttr_seconds < 604800 "
        "| stats avg(mttr_seconds) AS avg_mttr, median(mttr_seconds) AS med_mttr by urgency "
        "| eval avg_mttr_hours = round(avg_mttr / 3600, 1)"
    )
    return run_splunk_search(base_url, headers, query)


def collect_alert_quality(base_url, headers):
    """Collect alert disposition and quality metrics."""
    query = (
        "index=notable earliest=-30d "
        "| stats count AS total, "
        'sum(eval(if(status_label="Resolved - True Positive", 1, 0))) AS tp, '
        'sum(eval(if(status_label="Resolved - False Positive", 1, 0))) AS fp '
        "| eval tp_rate = round(tp / total * 100, 1) "
        "| eval fp_rate = round(fp / total * 100, 1) "
        "| eval signal_noise = round(tp / (fp + 0.01), 2)"
    )
    return run_splunk_search(base_url, headers, query)


def collect_analyst_productivity(base_url, headers):
    """Collect per-analyst productivity metrics."""
    query = (
        'index=notable earliest=-30d status_label="Resolved*" '
        "| stats count AS alerts_resolved, "
        "avg(eval((status_end - status_transition_time) / 60)) AS avg_triage_min "
        "by owner "
        "| eval alerts_per_day = round(alerts_resolved / 30, 1) "
        "| sort - alerts_resolved"
    )
    return run_splunk_search(base_url, headers, query)


def generate_report(mttd, mttr, quality, productivity):
    """Generate formatted SOC performance report."""
    report_date = datetime.utcnow().strftime("%B %Y")
    lines = [
        f"SOC PERFORMANCE REPORT - {report_date}",
        "=" * 50,
        "",
        "KEY METRICS (MTTD):",
    ]
    for row in mttd:
        lines.append(
            f"  {row.get('urgency', 'N/A'):15s} Avg: {row.get('avg_mttd_min', 'N/A')} min"
        )

    lines.append("\nKEY METRICS (MTTR):")
    for row in mttr:
        lines.append(
            f"  {row.get('urgency', 'N/A'):15s} Avg: {row.get('avg_mttr_hours', 'N/A')} hrs"
        )

    lines.append("\nALERT QUALITY:")
    for row in quality:
        lines.append(f"  Total Alerts:       {row.get('total', 'N/A')}")
        lines.append(f"  True Positive Rate:  {row.get('tp_rate', 'N/A')}%")
        lines.append(f"  False Positive Rate: {row.get('fp_rate', 'N/A')}%")
        lines.append(f"  Signal-to-Noise:     {row.get('signal_noise', 'N/A')}")

    lines.append("\nANALYST PRODUCTIVITY:")
    for row in productivity:
        lines.append(
            f"  {row.get('owner', 'N/A'):20s} {row.get('alerts_per_day', 'N/A')} alerts/day  "
            f"Avg triage: {row.get('avg_triage_min', 'N/A')} min"
        )

    report = "\n".join(lines)
    print(report)
    return report


def main():
    parser = argparse.ArgumentParser(description="SOC Metrics and KPI Tracking Agent")
    parser.add_argument("--splunk-url", default=SPLUNK_BASE, help="Splunk base URL")
    parser.add_argument("--username", default="admin", help="Splunk username")
    parser.add_argument("--password", required=True, help="Splunk password")
    parser.add_argument("--output", default="soc_metrics_report.json", help="Output JSON file")
    args = parser.parse_args()

    headers = authenticate_splunk(args.splunk_url, args.username, args.password)

    mttd = collect_mttd_metrics(args.splunk_url, headers)
    mttr = collect_mttr_metrics(args.splunk_url, headers)
    quality = collect_alert_quality(args.splunk_url, headers)
    productivity = collect_analyst_productivity(args.splunk_url, headers)

    generate_report(mttd, mttr, quality, productivity)

    output = {
        "generated_at": datetime.utcnow().isoformat(),
        "mttd_metrics": mttd,
        "mttr_metrics": mttr,
        "alert_quality": quality,
        "analyst_productivity": productivity,
    }
    with open(args.output, "w") as f:
        json.dump(output, f, indent=2)
    logger.info("Report saved to %s", args.output)


if __name__ == "__main__":
    main()
