package main

import (
	"context"
	// "fmt"
	"log"
	"math/rand"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	// This import path must match the module name and package name
	pb "sensor_go/weather_system"
)

const (
	address = "localhost:50051"
	stationID = "STATION_GO_001"
	// The correct secret key, must match the one in analytics_server.py
	VALID_AUTH_KEY = "SECRET_WEATHER_KEY_2025"
)

// Simulates sending streaming data (Client Streaming)
func streamWeatherData(client pb.WeatherAnalyticsServiceClient, authKey string) {

	// 1. Setup Metadata for Authentication:
	// The key is "authorization" and the value must start with "Bearer ".
	md := metadata.Pairs("authorization", "Bearer "+authKey)
	ctx := metadata.NewOutgoingContext(context.Background(), md)

	// Open the data stream (Client Streaming)
	stream, err := client.StreamWeatherData(ctx)
	if err != nil {
		log.Printf("❌ Failed to open stream: %v", err)
		return
	}

	log.Printf("--- Starting data transmission (Key: %s) ---", authKey)

	// Loop to send 20 readings
	for i := 0; i < 20; i++ {

		// Simulate random weather data reading
		temp := 20.0 + rand.Float64()*25.0 // Temperature between 20 and 45

		// 🚨 Alert Test (Status Error)
		// At reading 10, deliberately raise the temperature above the limit (45) to test server error handling.
		if i == 10 && authKey == VALID_AUTH_KEY {
			temp = 50.0
			log.Printf("🚨 Sending deliberately high reading to test alert: %.2f C", temp)
		}

		data := &pb.WeatherData{
			TemperatureCelsius: temp,
			HumidityPercent:    40.0 + rand.Float64()*40.0,
			PressureHpa:        980.0 + rand.Float64()*50.0,
			Timestamp:          time.Now().Unix(),
			StationId:          stationID,
		}

		if err := stream.Send(data); err != nil {
			// Connection will be cut here if authentication failed or server aborted
			log.Printf("❌ Failed to send data #%d: %v", i, err)
			break
		}

		if i < 19 {
			time.Sleep(500 * time.Millisecond) // Wait 0.5 seconds between readings
		}
	}

	// 2. Close the stream and receive final statistics
	stats, err := stream.CloseAndRecv()

	// 3. Examine the response (including alerts and errors)
	if err != nil {
		st, ok := status.FromError(err)
		if ok {
			// Check for Authentication Error (UNAUTHENTICATED)
			if st.Code() == codes.Unauthenticated {
				log.Printf("❌ Failed Auth Test Successful: Status Code = %v, Message = %s", st.Code(), st.Message())
			} else if st.Code() == codes.ResourceExhausted { // << FIX APPLIED HERE
				log.Printf("🔔 Alert Test Successful (Boundary Exceeded): Status Code = %v, Message = %s", st.Code(), st.Message())
			} else {
				log.Printf("❌ Failed to close stream or unexpected error: %v", err)
			}
		} else {
			log.Fatalf("❌ Failed to close stream: %v", err)
		}
		return
	}

	// If connection succeeded and no alert occurred (i.e., didn't send 50C)
	log.Printf("✅ Transmission successful. Final statistics received:")
	log.Printf("   > Average Temperature: %.2f C", stats.AvgTemperature)
	log.Printf("   > Report Time: %v", time.Unix(stats.ReportTime, 0).Format(time.Stamp))
}

func main() {
	// Setup connection to the Analytics Server
	conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("❌ Failed to connect to Analytics Server: %v", err)
	}
	defer conn.Close()

	// Create gRPC client stub
	client := pb.NewWeatherAnalyticsServiceClient(conn)

	// --- 1. Run 1: Successful Auth Test with extreme data (to trigger alert) ---
	log.Println("\n==============================================")
	log.Println("           Run 1: Valid Key to Test Alert")
	log.Println("==============================================")
	streamWeatherData(client, VALID_AUTH_KEY) // The correct key

	// --- 2. Run 2: Failed Authentication Test ---
	log.Println("\n==============================================")
	log.Println("           Run 2: Invalid Key to Test Auth")
	log.Println("==============================================")
	streamWeatherData(client, "INVALID_KEY") // The wrong key
}