// Package main provides the API Gateway service entry point.
package main

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"time"

	"git.dcentral.systems/toolz/goplt/internal/client"
	"git.dcentral.systems/toolz/goplt/internal/di"
	"git.dcentral.systems/toolz/goplt/internal/health"
	"git.dcentral.systems/toolz/goplt/internal/metrics"
	"git.dcentral.systems/toolz/goplt/internal/server"
	"git.dcentral.systems/toolz/goplt/pkg/config"
	"git.dcentral.systems/toolz/goplt/pkg/errorbus"
	"git.dcentral.systems/toolz/goplt/pkg/logger"
	"git.dcentral.systems/toolz/goplt/pkg/registry"
	"git.dcentral.systems/toolz/goplt/services/gateway"
	"go.opentelemetry.io/otel/trace"
	"go.uber.org/fx"
)

func main() {
	// Create DI container with core kernel services
	container := di.NewContainer(
		// Invoke lifecycle hooks
		fx.Invoke(di.RegisterLifecycleHooks),
		// Create API Gateway
		fx.Invoke(func(
			cfg config.ConfigProvider,
			log logger.Logger,
			healthRegistry *health.Registry,
			metricsRegistry *metrics.Metrics,
			errorBus errorbus.ErrorPublisher,
			tracer trace.TracerProvider,
			serviceRegistry registry.ServiceRegistry,
			clientFactory *client.ServiceClientFactory,
			lc fx.Lifecycle,
		) {
			// Create HTTP server using server foundation
			srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus, tracer)
			if err != nil {
				log.Error("Failed to create API Gateway server",
					logger.Error(err),
				)
				os.Exit(1)
			}

			// Setup gateway routes
			gateway, err := gateway.NewGateway(cfg, log, clientFactory, serviceRegistry)
			if err != nil {
				log.Error("Failed to create API Gateway",
					logger.Error(err),
				)
				os.Exit(1)
			}
			gateway.SetupRoutes(srv.Router())

			// Register with Consul
			gatewayPort := cfg.GetInt("gateway.port")
			if gatewayPort == 0 {
				gatewayPort = 8080
			}
			gatewayHost := cfg.GetString("gateway.host")
			if gatewayHost == "" {
				gatewayHost = "localhost"
			}

			serviceInstance := &registry.ServiceInstance{
				ID:      fmt.Sprintf("api-gateway-%d", os.Getpid()),
				Name:    "api-gateway",
				Address: gatewayHost,
				Port:    gatewayPort,
				Tags:    []string{"gateway", "http"},
				Metadata: map[string]string{
					"version": "1.0.0",
				},
			}

			// Register lifecycle hooks
			lc.Append(fx.Hook{
				OnStart: func(ctx context.Context) error {
					// Register with service registry
					if err := serviceRegistry.Register(ctx, serviceInstance); err != nil {
						log.Warn("Failed to register API Gateway with service registry",
							logger.Error(err),
						)
						// Continue anyway - gateway can work without registry
					} else {
						log.Info("API Gateway registered with service registry",
							logger.String("service_id", serviceInstance.ID),
						)
					}

					// Start HTTP server
					addr := fmt.Sprintf("%s:%d", cfg.GetString("server.host"), gatewayPort)
					log.Info("API Gateway starting",
						logger.String("addr", addr),
					)

					errChan := make(chan error, 1)
					go func() {
						if err := srv.Start(); err != nil && err != http.ErrServerClosed {
							log.Error("API Gateway server failed",
								logger.String("error", err.Error()),
							)
							errChan <- err
						}
					}()

					// Wait a short time to detect immediate binding errors
					select {
					case err := <-errChan:
						return fmt.Errorf("API Gateway failed to start: %w", err)
					case <-time.After(500 * time.Millisecond):
						log.Info("API Gateway started successfully",
							logger.String("addr", addr),
						)
						return nil
					}
				},
				OnStop: func(ctx context.Context) error {
					// Deregister from service registry
					if err := serviceRegistry.Deregister(ctx, serviceInstance.ID); err != nil {
						log.Warn("Failed to deregister API Gateway from service registry",
							logger.Error(err),
						)
					} else {
						log.Info("API Gateway deregistered from service registry")
					}

					// Shutdown HTTP server
					return srv.Shutdown(ctx)
				},
			})
		}),
	)

	// Create root context
	ctx := context.Background()

	// Start the application
	if err := container.Start(ctx); err != nil {
		log := logger.GetGlobalLogger()
		if log != nil {
			log.Error("Failed to start API Gateway",
				logger.Error(err),
			)
		} else {
			fmt.Fprintf(os.Stderr, "Failed to start API Gateway: %v\n", err)
		}
		os.Exit(1)
	}
}
