// Package main is the entry point for the mock dataplane manager server.
// This server mocks the dataplane-manager gRPC APIs for local development.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"

	dpmv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/hack/mock-dpm/admin"
	"github.com/tidbcloud/cluster-service-ng/hack/mock-dpm/services"
	"github.com/tidbcloud/cluster-service-ng/hack/mock-dpm/store"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

var (
	grpcPort  = flag.Int("grpc-port", 10000, "gRPC server port")
	adminPort = flag.Int("admin-port", 8080, "Admin HTTP server port")
)

func main() {
	flag.Parse()

	// Initialize in-memory store
	memStore := store.NewMemoryStore()

	// Create gRPC server
	grpcServer := grpc.NewServer(
		grpc.UnaryInterceptor(loggingInterceptor),
	)

	// Register services
	dataplaneSvc := services.NewDataPlaneService(memStore)
	bucketSvc := services.NewBucketService(memStore)
	loadbalancerSvc := services.NewLoadBalancerService(memStore)
	privatelinkSvc := services.NewPrivateLinkConnectionService(memStore)

	dpmv1.RegisterDataPlaneServiceServer(grpcServer, dataplaneSvc)
	dpmv1.RegisterBucketServiceServer(grpcServer, bucketSvc)
	dpmv1.RegisterLoadBalancerServiceServer(grpcServer, loadbalancerSvc)
	dpmv1.RegisterPrivateLinkConnectionServiceServer(grpcServer, privatelinkSvc)

	// Enable reflection for grpcurl
	reflection.Register(grpcServer)

	// Create admin HTTP server
	adminHandler := admin.NewHandler(memStore)
	adminMux := http.NewServeMux()
	adminMux.HandleFunc("/healthz", adminHandler.Healthz)
	adminMux.HandleFunc("/dump", adminHandler.Dump)
	adminMux.HandleFunc("/reset", adminHandler.Reset)

	adminServer := &http.Server{
		Addr:    fmt.Sprintf(":%d", *adminPort),
		Handler: adminMux,
	}

	// Start servers
	var wg sync.WaitGroup

	// Start gRPC server
	wg.Add(1)
	go func() {
		defer wg.Done()
		lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *grpcPort))
		if err != nil {
			log.Fatalf("Failed to listen on port %d: %v", *grpcPort, err)
		}
		log.Printf("Mock Dataplane Manager gRPC server listening on :%d", *grpcPort)
		if err := grpcServer.Serve(lis); err != nil {
			log.Printf("gRPC server stopped: %v", err)
		}
	}()

	// Start admin HTTP server
	wg.Add(1)
	go func() {
		defer wg.Done()
		log.Printf("Admin HTTP server listening on :%d", *adminPort)
		if err := adminServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("Admin server stopped: %v", err)
		}
	}()

	// Wait for shutdown signal
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	log.Println("Shutting down servers...")
	grpcServer.GracefulStop()
	if err := adminServer.Shutdown(context.Background()); err != nil {
		log.Printf("Admin server shutdown error: %v", err)
	}

	wg.Wait()
	log.Println("Servers stopped")
}

// loggingInterceptor logs all gRPC requests with sensitive data sanitized
func loggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	log.Printf("[gRPC] %s - request received", info.FullMethod)
	resp, err := handler(ctx, req)
	if err != nil {
		log.Printf("[gRPC] %s - error: %v", info.FullMethod, err)
	} else {
		log.Printf("[gRPC] %s - success", info.FullMethod)
	}
	return resp, err
}
