package de.serosystems.grx.example;

import com.google.protobuf.Empty;
import de.serosystems.proto.v3.grx.CommonProto;
import de.serosystems.proto.v3.grx.tunablechanneld.TunableChannelDProto;
import de.serosystems.proto.v3.grx.tunablechanneld.TunableChanneldGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

/**
 * Example: Use the TunableChanneld service to list tunable channels and query their
 * current configuration.
 *
 * <p>This example connects to the TunableChanneld service, lists all available tunable
 * channels, and for each channel queries the current center frequency, analog bandwidth,
 * sample rate, hardware gain, and available RX ports.</p>
 *
 * <p>Usage: {@code java TunableChannel [host]}</p>
 * <p>Default host: YOUR_GRX_IP</p>
 */
public class TunableChannel {

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

	/** TunableChanneld gRPC port. */
	private static final int TUNABLE_CHANNEL_PORT = 5309;

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

		try {
			// Create a blocking stub for the TunableChanneld service
			TunableChanneldGrpc.TunableChanneldBlockingStub stub =
					TunableChanneldGrpc.newBlockingStub(channel);

			// Step 1: List all tunable channels
			TunableChannelDProto.GetChannelsReply channelsReply =
					stub.getChannels(Empty.getDefaultInstance());

			System.out.printf("Found %d tunable channel(s).%n%n",
					channelsReply.getChannelsCount());

			if (channelsReply.getChannelsCount() == 0) {
				System.out.println("No tunable channels available on this device.");
				return;
			}

			// Step 2: For each channel, query its current settings
			for (CommonProto.RadioIdentification radioId : channelsReply.getChannelsList()) {
				System.out.printf("Channel: band=%s, per_band_index=%d%n",
						radioId.getBand().name(), radioId.getPerBandIndex());

				// Query center frequency
				TunableChannelDProto.GetCenterFrequencyReply freqReply =
						stub.getCenterFrequency(
								TunableChannelDProto.GetCenterFrequencyRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Center Frequency: %d Hz (%.3f MHz)%n",
						freqReply.getCenterFrequencyHz(),
						freqReply.getCenterFrequencyHz() / 1e6);

				// Query analog bandwidth
				TunableChannelDProto.GetAnalogBandwidthReply bwReply =
						stub.getAnalogBandwidth(
								TunableChannelDProto.GetAnalogBandwidthRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Analog Bandwidth: %d Hz (%.3f MHz)%n",
						bwReply.getAnalogBandwidthHz(),
						bwReply.getAnalogBandwidthHz() / 1e6);

				// Query sample rate
				TunableChannelDProto.GetSampleRateReply srReply =
						stub.getSampleRate(
								TunableChannelDProto.GetSampleRateRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Sample Rate:      %d Sps (%.3f MSps)%n",
						srReply.getSampleRateSps(),
						srReply.getSampleRateSps() / 1e6);

				// Query hardware gain
				TunableChannelDProto.GetHardwareGainReply gainReply =
						stub.getHardwareGain(
								TunableChannelDProto.GetHardwareGainRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Hardware Gain:    %d dB%n",
						gainReply.getHardwareGainDb());

				// Query current RX port
				TunableChannelDProto.GetRXPortReply rxPortReply =
						stub.getRXPort(
								TunableChannelDProto.GetRXPortRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Current RX Port:  %d%n", rxPortReply.getRxPort());

				// Query available RX ports with labels
				TunableChannelDProto.GetRXPortsReply rxPortsReply =
						stub.getRXPorts(
								TunableChannelDProto.GetRXPortsRequest.newBuilder()
										.setChannel(radioId)
										.build());
				System.out.printf("  Available RX Ports:%n");
				rxPortsReply.getRxPortToLabelMap().forEach((portId, label) ->
						System.out.printf("    Port %d: %s%n", portId, label));

				System.out.println();
			}

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