"""Flight-Tracking-Tools — Live-Flugverfolgung über OpenSky Network."""

import time

from mcp.server.fastmcp import FastMCP

from src.clients.opensky import OpenSkyClient

# Gemeinsame Client-Instanz für alle Tracking-Tools
_opensky = OpenSkyClient()


def register_tracking_tools(mcp: FastMCP):
    """Flugverfolgungs-Tools registrieren."""

    @mcp.tool()
    async def track_live_flights(
        lamin: float | None = None,
        lomin: float | None = None,
        lamax: float | None = None,
        lomax: float | None = None,
        limit: int = 50,
    ) -> dict:
        """Aktuelle Flüge weltweit oder in einem bestimmten Gebiet verfolgen.

        Ohne Koordinaten werden weltweite Flüge zurückgegeben (begrenzt auf limit).
        Mit Koordinaten wird ein bestimmtes Gebiet abgefragt (Bounding Box).

        Args:
            lamin: Minimaler Breitengrad — südliche Grenze (z.B. 47.0 für Süddeutschland)
            lomin: Minimaler Längengrad — westliche Grenze (z.B. 5.0 für Westdeutschland)
            lamax: Maximaler Breitengrad — nördliche Grenze (z.B. 55.0 für Norddeutschland)
            lomax: Maximaler Längengrad — östliche Grenze (z.B. 15.0 für Ostdeutschland)
            limit: Maximale Anzahl zurückgegebener Flüge (Standard: 50, Maximum: 200)
        """
        try:
            limit = min(limit, 200)
            data = await _opensky.get_all_states(
                lamin=lamin, lomin=lomin, lamax=lamax, lomax=lomax
            )

            states = data.get("states") or []
            flights = []
            for state in states[:limit]:
                parsed = _opensky._parse_state(state)
                # Nur Flüge mit Position anzeigen
                if parsed.get("latitude") is None:
                    continue
                flights.append({
                    "icao24": parsed.get("icao24", ""),
                    "callsign": parsed.get("callsign", ""),
                    "origin_country": parsed.get("origin_country", ""),
                    "latitude": parsed.get("latitude"),
                    "longitude": parsed.get("longitude"),
                    "altitude_m": parsed.get("baro_altitude"),
                    "velocity_ms": parsed.get("velocity"),
                    "heading": parsed.get("true_track"),
                    "vertical_rate_ms": parsed.get("vertical_rate"),
                    "on_ground": parsed.get("on_ground", False),
                })

            return {
                "timestamp": data.get("time", 0),
                "total_in_area": len(states),
                "returned": len(flights),
                "flights": flights,
            }
        except Exception as e:
            return {"error": f"Live-Flüge konnten nicht abgerufen werden: {e}"}

    @mcp.tool()
    async def track_flight(
        callsign: str | None = None,
        icao24: str | None = None,
    ) -> dict:
        """Einen bestimmten Flug per Callsign oder ICAO24-Adresse verfolgen.

        Mindestens einer der beiden Parameter muss angegeben werden.

        Args:
            callsign: Callsign des Flugs (z.B. "DLH400", "UAL123")
            icao24: ICAO24-Transponder-Adresse (z.B. "3c6752")
        """
        try:
            if not callsign and not icao24:
                return {"error": "Entweder callsign oder icao24 muss angegeben werden."}

            # Bei ICAO24 direkt filtern
            if icao24:
                data = await _opensky.get_states_by_icao24(icao24)
            else:
                # Bei Callsign alle Zustände holen und filtern
                data = await _opensky.get_all_states()

            states = data.get("states") or []
            results = []
            for state in states:
                parsed = _opensky._parse_state(state)
                # Callsign-Filter (case-insensitive)
                if callsign and parsed.get("callsign", "").upper() != callsign.upper():
                    continue
                results.append({
                    "icao24": parsed.get("icao24", ""),
                    "callsign": parsed.get("callsign", ""),
                    "origin_country": parsed.get("origin_country", ""),
                    "latitude": parsed.get("latitude"),
                    "longitude": parsed.get("longitude"),
                    "altitude_m": parsed.get("baro_altitude"),
                    "geo_altitude_m": parsed.get("geo_altitude"),
                    "velocity_ms": parsed.get("velocity"),
                    "heading": parsed.get("true_track"),
                    "vertical_rate_ms": parsed.get("vertical_rate"),
                    "on_ground": parsed.get("on_ground", False),
                    "squawk": parsed.get("squawk"),
                    "last_contact": parsed.get("last_contact"),
                })

            if not results:
                search_term = callsign if callsign else icao24
                return {"error": f"Kein Flug gefunden für: {search_term}"}

            return {
                "timestamp": data.get("time", 0),
                "count": len(results),
                "flights": results,
            }
        except Exception as e:
            return {"error": f"Flug konnte nicht verfolgt werden: {e}"}

    @mcp.tool()
    async def get_flight_path(icao24: str) -> dict:
        """Historischen Flugpfad (Trajektorie) eines Flugzeugs abrufen.

        Gibt den aktuellsten Track mit Wegpunkten zurück.

        Args:
            icao24: ICAO24-Transponder-Adresse des Flugzeugs (z.B. "3c6752")
        """
        try:
            data = await _opensky.get_track(icao24)

            # Wegpunkte aufbereiten
            path = data.get("path") or []
            waypoints = []
            for point in path:
                # Track-Array: [time, lat, lon, baro_alt, true_track, on_ground]
                waypoints.append({
                    "time": point[0] if len(point) > 0 else None,
                    "latitude": point[1] if len(point) > 1 else None,
                    "longitude": point[2] if len(point) > 2 else None,
                    "altitude_m": point[3] if len(point) > 3 else None,
                    "heading": point[4] if len(point) > 4 else None,
                    "on_ground": point[5] if len(point) > 5 else None,
                })

            return {
                "icao24": data.get("icao24", icao24),
                "callsign": (data.get("callsign") or "").strip(),
                "start_time": data.get("startTime"),
                "end_time": data.get("endTime"),
                "waypoint_count": len(waypoints),
                "waypoints": waypoints,
            }
        except Exception as e:
            return {"error": f"Flugpfad konnte nicht abgerufen werden: {e}"}

    @mcp.tool()
    async def get_airport_arrivals(
        airport_icao: str,
        hours: int = 2,
    ) -> dict:
        """Letzte Ankünfte an einem Flughafen abrufen (OpenSky).

        Args:
            airport_icao: ICAO-Code des Flughafens (z.B. "EDDF" für Frankfurt,
                "KJFK" für New York JFK, "EDDM" für München)
            hours: Zeitraum in Stunden zurück (Standard: 2, Maximum: 24)
        """
        try:
            hours = min(hours, 24)
            end = int(time.time())
            begin = end - (hours * 3600)

            arrivals = await _opensky.get_arrivals(airport_icao, begin, end)

            flights = []
            for flight in arrivals:
                flights.append({
                    "icao24": flight.get("icao24", ""),
                    "callsign": (flight.get("callsign") or "").strip(),
                    "departure_airport": flight.get("estDepartureAirport", ""),
                    "arrival_airport": flight.get("estArrivalAirport", ""),
                    "first_seen": flight.get("firstSeen"),
                    "last_seen": flight.get("lastSeen"),
                    "departure_horizontal_distance": flight.get(
                        "estDepartureAirportHorizDistance"
                    ),
                    "arrival_horizontal_distance": flight.get(
                        "estArrivalAirportHorizDistance"
                    ),
                })

            return {
                "airport": airport_icao.upper(),
                "period_hours": hours,
                "arrival_count": len(flights),
                "arrivals": flights,
            }
        except Exception as e:
            return {"error": f"Ankünfte konnten nicht abgerufen werden: {e}"}

    @mcp.tool()
    async def get_airport_departures(
        airport_icao: str,
        hours: int = 2,
    ) -> dict:
        """Letzte Abflüge von einem Flughafen abrufen (OpenSky).

        Args:
            airport_icao: ICAO-Code des Flughafens (z.B. "EDDF" für Frankfurt,
                "KJFK" für New York JFK, "EDDM" für München)
            hours: Zeitraum in Stunden zurück (Standard: 2, Maximum: 24)
        """
        try:
            hours = min(hours, 24)
            end = int(time.time())
            begin = end - (hours * 3600)

            departures = await _opensky.get_departures(airport_icao, begin, end)

            flights = []
            for flight in departures:
                flights.append({
                    "icao24": flight.get("icao24", ""),
                    "callsign": (flight.get("callsign") or "").strip(),
                    "departure_airport": flight.get("estDepartureAirport", ""),
                    "arrival_airport": flight.get("estArrivalAirport", ""),
                    "first_seen": flight.get("firstSeen"),
                    "last_seen": flight.get("lastSeen"),
                    "departure_horizontal_distance": flight.get(
                        "estDepartureAirportHorizDistance"
                    ),
                    "arrival_horizontal_distance": flight.get(
                        "estArrivalAirportHorizDistance"
                    ),
                })

            return {
                "airport": airport_icao.upper(),
                "period_hours": hours,
                "departure_count": len(flights),
                "departures": flights,
            }
        except Exception as e:
            return {"error": f"Abflüge konnten nicht abgerufen werden: {e}"}
