#!/usr/bin/env python3
"""
RTExit — Engagement Context Initializer
Creates _rtexit-output/data/engagement-context.json from config
All 7 agents read/write this shared context file.

Usage:
    python3 _rtexit/scripts/init-engagement.py --project-root .
"""

import json
import os
import sys
import argparse
from datetime import datetime, timezone

def load_toml_simple(path):
    """Minimal TOML parser for key=value pairs (no external deps)."""
    config = {}
    if not os.path.exists(path):
        return config
    with open(path, encoding='utf-8') as f:
        current_section = ''
        for line in f:
            line = line.strip()
            if not line or line.startswith('#'):
                continue
            if line.startswith('[') and line.endswith(']'):
                current_section = line[1:-1].strip()
                if current_section not in config:
                    config[current_section] = {}
                continue
            if '=' in line:
                key, _, val = line.partition('=')
                key = key.strip()
                val = val.strip().strip('"').strip("'")
                if current_section:
                    config.setdefault(current_section, {})[key] = val
                else:
                    config[key] = val
    return config


def init_context(project_root: str) -> dict:
    cfg = load_toml_simple(os.path.join(project_root, '_rtexit', 'config.user.toml'))
    eng = cfg.get('engagement', {})
    client = cfg.get('client', {})

    context = {
        "_meta": {
            "schema_version": "2.0",
            "created_at": datetime.now(timezone.utc).isoformat(),
            "updated_at": datetime.now(timezone.utc).isoformat(),
            "project_root": os.path.abspath(project_root)
        },

        # ── Engagement identity ──────────────────────────────────
        "engagement": {
            "ref":         eng.get("ref", "PENDING"),
            "client":      client.get("name", ""),
            "start_date":  eng.get("start_date", ""),
            "end_date":    eng.get("end_date", ""),
            "phase":       "planning",           # planning → recon → exploitation → post-exploitation → reporting
            "methodology": eng.get("methodology", "PTES"),
            "type":        eng.get("type", "web"),  # web|mobile|network|ad|cloud|full
            "sead_path":   "",
            "authorized":  False
        },

        # ── Targets (written by Commander, read by all) ──────────
        "targets": {
            "primary_domains": [],
            "subdomains": [],          # populated by Scout
            "live_hosts": [],          # populated by Scout
            "endpoints": [],           # populated by Scout/Breaker
            "api_endpoints": [],       # populated by Breaker
            "mobile_apps": [],         # populated by Navigator
            "cloud_accounts": [],      # populated by Ghost
            "ip_ranges": []
        },

        # ── Recon data (written by Scout) ─────────────────────────
        "recon": {
            "status":             "pending",   # pending → in_progress → complete
            "subdomains_found":   0,
            "live_hosts_found":   0,
            "emails_found":       [],
            "technologies":       {},          # host → [tech list]
            "open_ports":         {},          # host → [ports]
            "interesting_paths":  [],
            "js_secrets_found":   [],
            "cloud_buckets":      [],
            "historical_urls":    0,
            "workspace_path":     "docker/lab/workspace/recon/"
        },

        # ── Credentials (written by Breaker/Ghost, read by Ghost) ─
        "credentials": {
            "valid":   [],    # [{user, pass, service, source, found_by}]
            "hashes":  [],    # [{user, hash, type, source}]
            "tokens":  [],    # [{type, value, scope, expiry, service}]
            "api_keys": [],   # [{key, service, permissions}]
            "certificates": []
        },

        # ── Access gained (written by Breaker/Ghost) ──────────────
        "access": {
            "initial_access":    [],   # [{vector, target, method, timestamp}]
            "privileged_access": [],   # [{level, system, method}]
            "shells":            [],   # [{ip, type, port, user}]
            "pivot_points":      [],   # [{from, to, method}]
            "persistence":       []    # [{type, location, target}]
        },

        # ── Findings (written by all, aggregated by Scribe) ───────
        "findings": {
            "total":    0,
            "critical": 0,
            "high":     0,
            "medium":   0,
            "low":      0,
            "info":     0,
            "list": []
            # Each finding: {id, title, severity, target, cve, cvss,
            #                status, found_by, poc_path, verified}
        },

        # ── Phase tracking ────────────────────────────────────────
        "phases": {
            "planning":        {"status": "active",  "started": datetime.now(timezone.utc).isoformat(), "completed": None},
            "recon":           {"status": "pending", "started": None, "completed": None},
            "exploitation":    {"status": "pending", "started": None, "completed": None},
            "post_exploit":    {"status": "pending", "started": None, "completed": None},
            "reporting":       {"status": "pending", "started": None, "completed": None}
        },

        # ── Agent activity log ────────────────────────────────────
        "agent_log": [
            {
                "agent":     "commander",
                "action":    "engagement_initialized",
                "timestamp": datetime.now(timezone.utc).isoformat(),
                "note":      "engagement-context.json created"
            }
        ],

        # ── Notes / shared intelligence ───────────────────────────
        "notes": {
            "attack_vectors":    [],   # promising attack vectors found
            "blocked_paths":     [],   # WAF/block rules encountered
            "interesting_tech":  [],   # notable technologies
            "custom":            []    # free-form notes from any agent
        }
    }

    return context


def save_context(context: dict, project_root: str):
    out_dir = os.path.join(project_root, '_rtexit-output', 'data')
    os.makedirs(out_dir, exist_ok=True)
    path = os.path.join(out_dir, 'engagement-context.json')
    with open(path, 'w', encoding='utf-8') as f:
        json.dump(context, f, indent=2, ensure_ascii=False)
    return path


def update_context(project_root: str, agent: str, updates: dict):
    """
    Merge updates into existing engagement-context.json.
    Called by each agent to write their data.

    updates example:
    {
        "recon.subdomains_found": 142,
        "recon.status": "complete",
        "findings.high": 3,
        "phases.recon.completed": "2026-06-09T12:00:00Z"
    }
    """
    path = os.path.join(project_root, '_rtexit-output', 'data', 'engagement-context.json')
    if not os.path.exists(path):
        context = init_context(project_root)
    else:
        with open(path, encoding='utf-8') as f:
            context = json.load(f)

    # Apply dot-notation updates
    for key_path, value in updates.items():
        parts = key_path.split('.')
        target = context
        for part in parts[:-1]:
            target = target.setdefault(part, {})
        target[parts[-1]] = value

    # Update metadata
    context['_meta']['updated_at'] = datetime.now(timezone.utc).isoformat()

    # Append to agent log
    context['agent_log'].append({
        "agent":     agent,
        "action":    "context_updated",
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "keys":      list(updates.keys())
    })

    with open(path, 'w', encoding='utf-8') as f:
        json.dump(context, f, indent=2, ensure_ascii=False)

    return path


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='RTExit engagement context initializer')
    parser.add_argument('--project-root', default='.', help='Project root directory')
    parser.add_argument('--update', action='store_true', help='Update existing context')
    parser.add_argument('--agent', default='commander', help='Agent name for log')
    args = parser.parse_args()

    root = os.path.abspath(args.project_root)
    ctx = init_context(root)
    path = save_context(ctx, root)
    print(f"[+] Engagement context initialized: {path}")
    print(f"    Engagement: {ctx['engagement']['ref']}")
    print(f"    Phase:      {ctx['engagement']['phase']}")
    print(f"    Targets:    {len(ctx['targets']['primary_domains'])} domains configured")
    print(f"\n    All 7 agents will read/write this file.")
    print(f"    Schema: _rtexit-output/data/engagement-context.json")
