"""
A simple tool that tries to guess what kind of service is running on a local port.

This module combines two smaller probes: a TCP check (to see if the port is open)
and a banner check (to see if the service sends any text when we connect). By
putting these together, we can make basic guesses like “this looks like SSH” or
“this might be an HTTP server.”

For safety, the probe only works on local addresses. If the host isn’t local,
we stop immediately so the agent can’t scan other machines.

The result is returned in a standard format (`ServiceProbeResult`) that includes
whether the port was reachable, whether we got a banner, what service we think
it might be, and how confident we are. This makes it easy for the rest of the
agent to understand what’s happening on a port without needing to know the
details of TCP or banner parsing.
"""


from dataclasses import dataclass
from .utility import resolve_local_address
from. tcp_probe import tcp_probe
from .banner_probe import banner_probe

from .probe_schema import (
    Reachability,
    BannerStatus,
    Classification,
    ClassificationReason,
    Service,
    ServiceProbeResult,
)


def service_probe(local_address_mode: str, port: int) -> ServiceProbeResult:
    """
    High-level service classifier using unified meta-probe schema.
    """

    # --- Local-only guardrail ---
    local_address = resolve_local_address(local_address_mode)
    if not local_address:
        return ServiceProbeResult(
            reachability="unreachable",
            banner_status="banner_error",
            classification="unclassified",
            classification_reason="tcp_failed",
            service="unknown",
            confidence=0.0,
            tcp=None,
            banner=None,
        )

    # --- TCP probe ---
    tcp = tcp_probe(local_address_mode, port)

    if tcp.classification.upper() != "OPEN_TCP":
        return ServiceProbeResult(
            reachability="unreachable",
            banner_status="banner_error",
            classification="unclassified",
            classification_reason="tcp_failed",
            service="unknown",
            confidence=0.0,
            tcp=tcp,
            banner=None,
        )

    # TCP succeeded
    reachability: Reachability = "reachable"

    # --- Banner probe ---
    banner = banner_probe(local_address_mode, port)

    # Banner failure modes
    if banner.error:
        # Distinguish timeout vs other errors
        if "timed out" in (banner.error or "").lower():
            banner_status: BannerStatus = "read_timeout"
            classification_reason: ClassificationReason = "no_banner"
        else:
            banner_status = "banner_error"
            classification_reason = "banner_failed"

        return ServiceProbeResult(
            reachability=reachability,
            banner_status=banner_status,
            classification="unclassified",
            classification_reason=classification_reason,
            service="unknown",
            confidence=0.0,
            tcp=tcp,
            banner=banner,
        )

    # Banner received
    banner_status = "banner_received"

    # --- Classification logic ---
    text = banner.decoded_text or ""

    if text.startswith("SSH-"):
        return ServiceProbeResult(
            reachability=reachability,
            banner_status=banner_status,
            classification="classified",
            classification_reason="ssh",
            service="ssh",
            confidence=0.9,
            tcp=tcp,
            banner=banner,
        )

    if text.startswith("HTTP/1."):
        return ServiceProbeResult(
            reachability=reachability,
            banner_status=banner_status,
            classification="classified",
            classification_reason="http",
            service="http",
            confidence=0.9,
            tcp=tcp,
            banner=banner,
        )

    # Banner received but not recognized
    return ServiceProbeResult(
        reachability=reachability,
        banner_status=banner_status,
        classification="unclassified",
        classification_reason="unknown_service",
        service="unknown",
        confidence=0.2,
        tcp=tcp,
        banner=banner,
    )



if __name__ == "__main__":
    mode = "primary_ipv4"
    port = 445

    print(f"Running service_probe({mode}, {port})...\n")

    result = service_probe(mode, port)

    print("=== Service Probe Summary ===")
    print(f"Reachability          : {result.reachability}")
    print(f"Banner Status         : {result.banner_status}")
    print(f"Classification        : {result.classification}")
    print(f"Classification Reason : {result.classification_reason}")
    print(f"Service               : {result.service}")
    print(f"Confidence            : {result.confidence}")

    print("\n--- TCP Probe (raw) ---")
    print(result.tcp)

    print("\n--- Banner Probe (raw) ---")
    print(result.banner)

