package de.serosystems.grx.example;

import com.google.protobuf.Empty;
import de.serosystems.proto.v3.grx.receiverd.ReceiverDProto;
import de.serosystems.proto.v3.grx.receiverd.ReceiverdGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Locale;

/**
 * Example: Retrieve the list of currently tracked aircraft from the GRX receiver.
 *
 * <p>This example connects to the Receiverd service, fetches the current state vector
 * list, and prints a summary table of all tracked aircraft including their ICAO address,
 * callsign, position, altitude, and speed.</p>
 *
 * <p>Usage: {@code java TrackedAircraft [host]}</p>
 * <p>Default host: YOUR_GRX_IP</p>
 */
public class TrackedAircraft {

	/** Default IP address of the GRX receiver. */
	private static final String DEFAULT_HOST = "YOUR_GRX_IP";

	/** Receiverd gRPC port. */
	private static final int RECEIVERD_PORT = 5303;

	public static void main(String[] args) {
		// Use the first CLI argument as hostname, or fall back to the default
		String host = args.length > 0 ? args[0] : DEFAULT_HOST;

		// Create a plaintext gRPC channel to the Receiverd service
		ManagedChannel channel = ManagedChannelBuilder.forAddress(host, RECEIVERD_PORT)
				.usePlaintext()
				.build();

		try {
			// Create a blocking (synchronous) stub for the Receiverd service
			ReceiverdGrpc.ReceiverdBlockingStub stub = ReceiverdGrpc.newBlockingStub(channel);

			// Call GetStateVectors to get all currently tracked aircraft
			ReceiverDProto.StateVectorList stateVectors =
					stub.getStateVectors(Empty.getDefaultInstance());

			// Count how many aircraft have a valid ADS-B position
			long withPosition = stateVectors.getStateVectorsList().stream()
					.filter(ReceiverDProto.StateVectorList.StateVector::hasPosition)
					.count();

			System.out.printf("Tracked aircraft: %d (of which %d have an ADS-B position)%n%n",
					stateVectors.getStateVectorsCount(), withPosition);

			// Print table header
			System.out.printf("%-8s %-10s %-8s %10s %10s %8s %6s %7s%n",
					"ICAO24", "Callsign", "Country", "Lat", "Lon", "Alt[ft]", "Spd", "Trk");
			System.out.println("-".repeat(78));

			// Iterate over each state vector and print a summary row
			for (ReceiverDProto.StateVectorList.StateVector sv : stateVectors.getStateVectorsList()) {

				// Format the ICAO24 address as 6-digit hex
				String icao = String.format("%06X",
						sv.getQualifiedAddress().getAddress());

				// Callsign may be empty if not yet received
				String callsign = sv.getIdentification().isEmpty() ? "-" : sv.getIdentification();

				// Country as determined by the ICAO address block
				String country = sv.getCountry().isEmpty() ? "-" : sv.getCountry();

				// Position fields: only valid if position sub-message is present
				String lat = "-";
				String lon = "-";
				if (sv.hasPosition()) {
					lat = String.format(Locale.US, "%10.5f", sv.getPosition().getLatitude());
					lon = String.format(Locale.US, "%10.5f", sv.getPosition().getLongitude());
				}

				// Altitude: valid if last_update timestamp > 0
				String alt = sv.getBarometricAltitudeLastUpdate() > 0
						? String.valueOf(sv.getBarometricAltitude())
						: "-";

				// Speed: valid if last_update timestamp > 0
				String spd = sv.getSpeedOverGroundLastUpdate() > 0
						? String.valueOf(sv.getSpeedOverGround())
						: "-";

				// Track angle: valid if last_update timestamp > 0
				String trk = sv.getTrackAngleLastUpdate() > 0
						? String.valueOf(sv.getTrackAngle())
						: "-";

				System.out.printf("%-8s %-10s %-8s %10s %10s %8s %6s %7s%n",
						icao, callsign, country, lat, lon, alt, spd, trk);
			}

		} catch (Exception e) {
			System.err.println("Error retrieving state vectors: " + e.getMessage());
			e.printStackTrace();
		} finally {
			// Always shut down the channel to release resources
			channel.shutdownNow();
		}
	}
}
