package com.weather.monitoring.grpc;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;

// Generated files are now easily imported

import java.util.concurrent.TimeUnit;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DashboardClient {
    private final ManagedChannel channel;
    private final WeatherAnalyticsServiceGrpc.WeatherAnalyticsServiceBlockingStub blockingStub;
    private final WeatherAnalyticsServiceGrpc.WeatherAnalyticsServiceStub asyncStub;

    private static final String ANALYTICS_ADDRESS = "localhost:50051";

    public DashboardClient(String host, int port) {
        // Create an Insecure Channel
        channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();

        // Create stubs for synchronous (blocking) and asynchronous (streaming) calls
        blockingStub = WeatherAnalyticsServiceGrpc.newBlockingStub(channel);
        asyncStub = WeatherAnalyticsServiceGrpc.newStub(channel);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    /**
     * Unary RPC: Manually requests the last stored report.
     */
    public void getManualReport() {
        System.out.println("\n--- 🔵 Requesting Manual Report (Unary RPC) ---");
        try {
            // Use Blocking Stub for Unary RPC
            Weather.Empty request = Weather.Empty.newBuilder().build();

            // Call GetLastReport
            Weather.WeatherStats stats = blockingStub.getLastReport(request);

            String reportTime = new SimpleDateFormat("HH:mm:ss").format(new Date(stats.getReportTime() * 1000L));

            System.out.println("✅ Last Stored Report (at " + reportTime + "):");
            System.out.printf("   > Avg Temp: %.2f C\n", stats.getAvgTemperature());
            System.out.printf("   > Avg Humidity: %.2f %%\n", stats.getAvgHumidity());
            System.out.printf("   > Avg Pressure: %.2f hPa\n", stats.getAvgPressure());

        } catch (Exception e) {
            Status status = Status.fromThrowable(e);
            if (status.getCode() == Status.Code.NOT_FOUND) {
                System.err.println("❌ Error: No reports currently stored in DB. Status: " + status.getDescription());
            } else {
                System.err.println("❌ Error requesting manual report. Details: " + status.getDescription());
            }
        }
    }

    /**
     * Server Streaming: Subscribes to continuous reports from the Analytics Server.
     */
    public void streamAnalytics() {
        System.out.println("\n--- 🟢 Subscribing to Continuous Analysis Stream (Server Streaming) ---");

        // Use Async Stub for Server Streaming
        Weather.Empty request = Weather.Empty.newBuilder().build();

        asyncStub.streamAnalytics(request, new StreamObserver<Weather.WeatherStats>() {
            @Override
            public void onNext(Weather.WeatherStats stats) {
                // Receive data
                String reportTime = new SimpleDateFormat("HH:mm:ss").format(new Date(stats.getReportTime() * 1000L));

                System.out.printf("\n[%s] Updated Analysis Report -----------------\n", reportTime);
                System.out.printf("  🌡️ Avg Temp: %.2f C\n", stats.getAvgTemperature());
                System.out.printf("  💧 Avg Humidity: %.2f %%\n", stats.getAvgHumidity());
                System.out.printf("  💨 Avg Pressure: %.2f hPa\n", stats.getAvgPressure());
            }

            @Override
            public void onError(Throwable t) {
                // Handle errors
                Status status = Status.fromThrowable(t);
                System.err.println("❌ Stream Error from server. Details: " + status.getDescription());
            }

            @Override
            public void onCompleted() {
                // Stream completion (if server terminates it)
                System.out.println("--- 🛑 Analysis Stream Completed ---");
            }
        });
    }

    public static void main(String[] args) throws InterruptedException {
        DashboardClient client = new DashboardClient("localhost", 50051);
        try {
            // 1. Request a manual report immediately
            client.getManualReport();

            // 2. Start the continuous report stream (will run in the background)
            client.streamAnalytics();

            // Keep the main thread running indefinitely to receive the stream
            Thread.sleep(Long.MAX_VALUE);
        } finally {
            client.shutdown();
        }
    }
}