#!/usr/bin/env python3
# For authorized testing in lab/CTF environments only
"""Phishing simulation campaign agent using requests to interact with GoPhish API."""

import argparse
import json
import logging
import sys
from datetime import datetime

try:
    import requests
except ImportError:
    sys.exit("requests is required: pip install requests")

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


class GoPhishClient:
    """Client for the GoPhish REST API."""

    def __init__(self, base_url: str, api_key: str, verify_ssl: bool = False):
        self.base_url = base_url.rstrip("/")
        self.session = requests.Session()
        self.session.headers.update({"Authorization": f"Bearer {api_key}"})
        self.session.verify = verify_ssl

    def _get(self, endpoint: str) -> dict:
        resp = self.session.get(f"{self.base_url}/api/{endpoint}", timeout=30)
        resp.raise_for_status()
        return resp.json()

    def _post(self, endpoint: str, data: dict) -> dict:
        resp = self.session.post(f"{self.base_url}/api/{endpoint}", json=data, timeout=30)
        resp.raise_for_status()
        return resp.json()

    def create_sending_profile(self, name: str, smtp_from: str, host: str,
                                username: str, password: str) -> dict:
        """Create an SMTP sending profile."""
        payload = {
            "name": name,
            "from_address": smtp_from,
            "host": host,
            "username": username,
            "password": password,
            "ignore_cert_errors": True,
        }
        result = self._post("smtp/", payload)
        logger.info("Created sending profile: %s (id=%s)", name, result.get("id"))
        return result

    def create_email_template(self, name: str, subject: str, html_body: str,
                               text_body: str = "") -> dict:
        """Create a phishing email template with tracking."""
        payload = {
            "name": name,
            "subject": subject,
            "html": html_body,
            "text": text_body,
            "capture_credentials": True,
            "capture_passwords": True,
        }
        result = self._post("templates/", payload)
        logger.info("Created email template: %s (id=%s)", name, result.get("id"))
        return result

    def create_landing_page(self, name: str, html: str, capture_creds: bool = True,
                             redirect_url: str = "") -> dict:
        """Create a credential harvesting landing page."""
        payload = {
            "name": name,
            "html": html,
            "capture_credentials": capture_creds,
            "capture_passwords": True,
            "redirect_url": redirect_url,
        }
        result = self._post("pages/", payload)
        logger.info("Created landing page: %s (id=%s)", name, result.get("id"))
        return result

    def import_targets(self, group_name: str, targets: list) -> dict:
        """Import target email list as a user group."""
        payload = {
            "name": group_name,
            "targets": [{"email": t["email"], "first_name": t.get("first_name", ""),
                         "last_name": t.get("last_name", ""), "position": t.get("position", "")}
                        for t in targets],
        }
        result = self._post("groups/", payload)
        logger.info("Created target group '%s' with %d targets", group_name, len(targets))
        return result

    def launch_campaign(self, name: str, template_id: int, page_id: int,
                         smtp_id: int, group_ids: list, url: str) -> dict:
        """Launch the phishing campaign."""
        payload = {
            "name": name,
            "template": {"id": template_id},
            "page": {"id": page_id},
            "smtp": {"id": smtp_id},
            "groups": [{"id": gid} for gid in group_ids],
            "url": url,
            "launch_date": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S+00:00"),
        }
        result = self._post("campaigns/", payload)
        logger.info("Launched campaign '%s' (id=%s)", name, result.get("id"))
        return result

    def get_campaign_results(self, campaign_id: int) -> dict:
        """Retrieve campaign results and metrics."""
        return self._get(f"campaigns/{campaign_id}/results")

    def get_campaign_summary(self, campaign_id: int) -> dict:
        """Get summary statistics for a campaign."""
        result = self._get(f"campaigns/{campaign_id}/summary")
        return result

    def list_campaigns(self) -> list:
        """List all campaigns."""
        return self._get("campaigns/")


def compute_metrics(results: dict) -> dict:
    """Compute phishing simulation success metrics from campaign results."""
    timeline = results.get("timeline", [])
    total = results.get("stats", {}).get("total", 0)
    sent = sum(1 for e in timeline if e.get("message") == "Email Sent")
    opened = sum(1 for e in timeline if e.get("message") == "Email Opened")
    clicked = sum(1 for e in timeline if e.get("message") == "Clicked Link")
    submitted = sum(1 for e in timeline if e.get("message") == "Submitted Data")
    reported = sum(1 for e in timeline if e.get("message") == "Email Reported")

    return {
        "total_targets": total,
        "emails_sent": sent,
        "emails_opened": opened,
        "links_clicked": clicked,
        "credentials_submitted": submitted,
        "reported_to_it": reported,
        "click_rate": f"{(clicked / total * 100):.1f}%" if total else "0%",
        "submission_rate": f"{(submitted / total * 100):.1f}%" if total else "0%",
        "report_rate": f"{(reported / total * 100):.1f}%" if total else "0%",
    }


def main():
    parser = argparse.ArgumentParser(description="Phishing Simulation Campaign Agent")
    parser.add_argument("--gophish-url", required=True, help="GoPhish server URL")
    parser.add_argument("--api-key", required=True, help="GoPhish API key")
    parser.add_argument("--action", choices=["launch", "results", "list"], default="list")
    parser.add_argument("--campaign-id", type=int, help="Campaign ID for results")
    parser.add_argument("--output", default="phishing_report.json")
    args = parser.parse_args()

    client = GoPhishClient(args.gophish_url, args.api_key)

    if args.action == "list":
        campaigns = client.list_campaigns()
        print(json.dumps(campaigns, indent=2, default=str))
    elif args.action == "results" and args.campaign_id:
        results = client.get_campaign_results(args.campaign_id)
        metrics = compute_metrics(results)
        with open(args.output, "w") as f:
            json.dump(metrics, f, indent=2)
        logger.info("Metrics saved to %s", args.output)
        print(json.dumps(metrics, indent=2))
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
