package de.serosystems.grx.example;

import com.google.protobuf.Empty;
import de.serosystems.proto.v3.grx.monitord.MonitorDProto;
import de.serosystems.proto.v3.grx.monitord.MonitordGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.Locale;

/**
 * Example: Retrieve GNSS (GPS) status information from the GRX receiver.
 *
 * <p>This example connects to the Monitord service and queries the current GNSS
 * information, including fix type, position, satellite count, timing, and accuracy
 * estimates.</p>
 *
 * <p>Usage: {@code java GNSSStatus [host]}</p>
 * <p>Default host: YOUR_GRX_IP</p>
 */
public class GNSSStatus {

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

	/** Monitord gRPC port. */
	private static final int MONITORD_PORT = 5305;

	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 Monitord service
		ManagedChannel channel = ManagedChannelBuilder.forAddress(host, MONITORD_PORT)
				.usePlaintext()
				.build();

		try {
			// Create a blocking (synchronous) stub for the Monitord service
			MonitordGrpc.MonitordBlockingStub stub = MonitordGrpc.newBlockingStub(channel);

			// Call GetGNSSInformation to retrieve current GNSS data
			MonitorDProto.GNSSInformation info =
					stub.getGNSSInformation(Empty.getDefaultInstance());

			// Extract position and timing sub-messages for convenience
			MonitorDProto.GNSSInformation.Position pos = info.getPosition();
			MonitorDProto.GNSSInformation.Timing timing = info.getTiming();

			// Print fix and position information
			System.out.printf("%-25s: %s%n", "Fix Type", pos.getFixType());
			System.out.printf("%-25s: %d%n", "Satellites Used", pos.getSatsUsed());
			System.out.printf(Locale.US, "%-25s: %.6f, %.6f%n",
					"Position (lat, lon)", pos.getLatitude(), pos.getLongitude());
			System.out.printf(Locale.US, "%-25s: %.1f m%n", "Height", pos.getHeight());
			System.out.printf(Locale.US, "%-25s: %.2f m%n",
					"Horizontal Accuracy", pos.getHorizontalAccuracy());
			System.out.printf(Locale.US, "%-25s: %.2f m%n",
					"Vertical Accuracy", pos.getVerticalAccuracy());

			// Print timing information
			MonitorDProto.GNSSInformation.Timing.UTC utc = timing.getUtc();
			if (utc.getValid()) {
				System.out.printf("%-25s: %04d-%02d-%02d %02d:%02d:%02d (Standard: %s)%n",
						"UTC Time",
						utc.getYear(), utc.getMonth(), utc.getDay(),
						utc.getHour(), utc.getMin(), utc.getSec(),
						utc.getStandard().name());
			} else {
				System.out.printf("%-25s: not valid%n", "UTC Time");
			}

			System.out.printf("%-25s: %d ns%n", "GNSS Time Accuracy", timing.getGnssTimeAccuracy());
			System.out.printf("%-25s: %d ns%n", "Overall Time Accuracy", timing.getOverallTimeAccuracy());
			System.out.printf("%-25s: %s%n", "Time Pulse Locked", timing.getTimePulseLocked());
			System.out.printf("%-25s: %s%n", "Disciplining Source",
					timing.getDiscipliningSource().name());

			// Print holdover oscillator info if present
			if (info.hasHoldoverOscillator()) {
				MonitorDProto.GNSSInformation.HoldoverOscillator ho = info.getHoldoverOscillator();
				System.out.printf("%n--- Holdover Oscillator ---%n");
				System.out.printf("%-25s: %s%n", "Schema", ho.getSchema().name());
				System.out.printf("%-25s: %s%n", "Model", ho.getModel());
				System.out.printf("%-25s: %d s%n", "Holdover Active", ho.getHoldoverActiveSeconds());
				System.out.printf("%-25s: %s%n", "Ready for Holdover", ho.getIsReadyForHoldover());
			}

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