"""FastMCP server for MCP Network JCD."""

from mcp.server.fastmcp import FastMCP

from mcp_network_jcd.tools.cisco import cisco_ios_query
from mcp_network_jcd.tools.f5 import f5_list, f5_stats
from mcp_network_jcd.tools.paloalto import paloalto_query

mcp = FastMCP("MCP Network JCD")


@mcp.tool()
def paloalto_query_tool(
    host: str,
    commands: list[str],
    port: int = 22,
    timeout: int = 30,
) -> dict:
    """Query Palo Alto firewall via SSH. Creds from env: PALOALTO_USERNAME, PALOALTO_PASSWORD. Input: host*, commands* (1-10), port (22), timeout (30s). Output: {success, device, results[], total_duration_ms, timestamp}. IMPORTANT: Avoid large outputs (MB). Use filtered commands: "show routing route | match 10.14", "test security-policy-match from ZONE to ZONE source IP destination IP protocol 6 destination-port 443", "show interface logical". Avoid unfiltered: "show running security-policy", "show session all"."""
    return paloalto_query(host=host, commands=commands, port=port, timeout=timeout)


@mcp.tool()
def cisco_ios_query_tool(
    host: str,
    commands: list[str],
    port: int = 22,
    timeout: int = 30,
) -> dict:
    """Query Cisco IOS device via SSH. Creds from env: CISCO_USERNAME, CISCO_PASSWORD, CISCO_ENABLE_PASSWORD (optional). Input: host*, commands* (1-10), port (22), timeout (30s). Output: {success, device, results[], total_duration_ms, timestamp}. IMPORTANT: Avoid large outputs (MB). Use filtered commands: "show ip route | include 10.0", "show running-config | section interface". Avoid unfiltered: "show running-config", "show ip route"."""
    return cisco_ios_query(host=host, commands=commands, port=port, timeout=timeout)


@mcp.tool()
def f5_list_tool(
    host: str,
    object_type: str,
    object_name: str = "",
    timeout: int = 20,
    sub_collection: str = "",
    name_filter: str = "",
) -> dict:
    """List or show F5 BIG-IP LTM object config via iControl REST API. Creds from env: F5_USERNAME, F5_PASSWORD. Input: host*, object_type* (virtual, pool, irule, profile), object_name (empty=list all), timeout (20s), sub_collection (members|policies|profiles), name_filter (case-insensitive substring match on name/fullPath/destination, like grep). Output: {success, host, data, error, duration_ms, timestamp}. READ-ONLY. IMPORTANT: Use name_filter to search objects by name or destination IP instead of listing all (avoids large output). Sub-collections: pool supports "members", virtual supports "policies" and "profiles". VIP investigation workflow: 1) Search virtuals by name or IP (object_type="virtual", name_filter="THOR" or name_filter="10.231.25.247"). 2) Get VIP detail (object_name="VIP_NAME") to see pool, persistence, sourceAddressTranslation, enabled/disabled. 3) If no pool on VIP, get policies (sub_collection="policies") to find routing rules (host-based forwarding to pools). 4) Get pool members (object_type="pool", object_name="POOL", sub_collection="members") to see backend IPs, state (up/down), session status. 5) Get VIP profiles (sub_collection="profiles") to see SSL, HTTP, persistence profiles."""
    return f5_list(host=host, object_type=object_type, object_name=object_name, timeout=timeout, sub_collection=sub_collection, name_filter=name_filter)


@mcp.tool()
def f5_stats_tool(
    host: str,
    object_type: str,
    object_name: str,
    timeout: int = 20,
) -> dict:
    """Show statistics for an F5 BIG-IP LTM object via iControl REST API. Creds from env: F5_USERNAME, F5_PASSWORD. Input: host*, object_type* (virtual, pool, irule, profile), object_name*, timeout (20s). Output: {success, host, data, error, duration_ms, timestamp}. READ-ONLY. Stats are nested under data.entries[url].nestedStats.entries. Key VIP stats: status.availabilityState (available/offline/unknown), status.enabledState, clientside.curConns, clientside.totConns, clientside.bitsIn, clientside.bitsOut, totRequests. Key pool stats: status.availabilityState, activeMemberCnt, memberCnt, curSessions, serverside.curConns, serverside.totConns, serverside.bitsIn, serverside.bitsOut, totRequests. A VIP with availabilityState=unknown usually means no pool is directly assigned (use f5_list_tool with sub_collection="policies" to find routing rules)."""
    return f5_stats(host=host, object_type=object_type, object_name=object_name, timeout=timeout)


def main() -> None:
    """Run the MCP server."""
    mcp.run()


if __name__ == "__main__":
    main()
