import docker
import requests
import time
import socket
import json
import os

# Configuration
# SERVER_URL = "http://localhost:8000" # Change this to the Manager's IP
SERVER_URL = os.getenv("MANAGER_URL", "https://waf.kemenimipas.go.id")
SERVER_NAME = os.getenv("SERVER_NAME", socket.gethostname())
POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "30"))

def get_docker_client():
    try:
        return docker.from_env()
    except Exception as e:
        print(f"Error connecting to Docker: {e}")
        return None

def scan_and_report():
    client = get_docker_client()
    if not client:
        return

    try:
        containers = client.containers.list()
        print(f"Found {len(containers)} running containers.")
        
        for container in containers:
            # Basic info
            name = container.name
            
            # Network info (trying to get the first IP found)
            # Use bridge network IP usually
            ip_address = None
            networks = container.attrs['NetworkSettings']['Networks']
            for net_name, net_conf in networks.items():
                ip_address = net_conf.get('IPAddress')
                if ip_address:
                    break
            
            if not ip_address:
                continue

            # Ports
            # We need to report internal ports that the service listens on.
            # Docker reports 'ExposedPorts' or 'Ports'.
            # 'Ports' example: {'80/tcp': [{'HostIp': '0.0.0.0', 'HostPort': '32768'}]}
            # We want the container port (e.g. 80)
            
            ports_config = container.attrs['NetworkSettings']['Ports']
            
            # If no ports exposed, skip or report default?
            # Let's verify exposed ports.
            
            target_ports = []
            if ports_config:
                for port_proto, host_bindings in ports_config.items():
                    # port_proto is "80/tcp"
                    port = int(port_proto.split('/')[0])
                    target_ports.append(port)
            
            # Also check 'ExposedPorts' config if Ports is empty (internal only)
            if not target_ports:
                 exposed = container.attrs['Config'].get('ExposedPorts')
                 if exposed:
                     for port_proto in exposed:
                    port = int(port_proto.split('/')[0])
                    target_ports.append(port)

            if not target_ports:
                target_ports = [80] # Default fallback?

            for port in target_ports:
                payload = {
                    "server_name": SERVER_NAME,
                    "container_name": name,
                    "ip_address": ip_address,
                    "port": port
                }
                
                try:
                    url = f"{SERVER_URL}/api/agents/register"
                    r = requests.post(url, json=payload)
                    if r.status_code == 200:
                        print(f"Reported: {name} ({ip_address}:{port})")
                    else:
                        print(f"Failed to report {name}: {r.status_code} - {r.text}")
                except Exception as e:
                    print(f"Connection error to Manager: {e}")

    except Exception as e:
        print(f"Error during scan: {e}")

if __name__ == "__main__":
    print(f"Starting Docker Agent on {SERVER_NAME}")
    print(f"Reporting to: {SERVER_URL}")
    
    while True:
        scan_and_report()
        time.sleep(POLL_INTERVAL)
