// Package gateway provides API Gateway implementation.
package gateway

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"

	"git.dcentral.systems/toolz/goplt/internal/client"
	"git.dcentral.systems/toolz/goplt/pkg/config"
	"git.dcentral.systems/toolz/goplt/pkg/logger"
	"git.dcentral.systems/toolz/goplt/pkg/registry"
	"github.com/gin-gonic/gin"
)

// Gateway handles routing requests to backend services.
type Gateway struct {
	config        config.ConfigProvider
	log           logger.Logger
	clientFactory *client.ServiceClientFactory
	registry      registry.ServiceRegistry
	routes        []RouteConfig
}

// RouteConfig defines a route configuration.
type RouteConfig struct {
	Path         string
	Service      string
	AuthRequired bool
}

// NewGateway creates a new API Gateway instance.
func NewGateway(
	cfg config.ConfigProvider,
	log logger.Logger,
	clientFactory *client.ServiceClientFactory,
	reg registry.ServiceRegistry,
) (*Gateway, error) {
	// Load route configurations
	routes := loadRoutes(cfg)

	return &Gateway{
		config:        cfg,
		log:           log,
		clientFactory: clientFactory,
		registry:      reg,
		routes:        routes,
	}, nil
}

// SetupRoutes configures routes on the Gin router.
func (g *Gateway) SetupRoutes(router *gin.Engine) {
	// Setup route handlers
	for _, route := range g.routes {
		route := route // Capture for closure
		router.Any(route.Path, g.handleRoute(route))
	}

	// Default handler for unmatched routes
	router.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{
			"error": "Route not found",
			"path":  c.Request.URL.Path,
		})
	})
}

// handleRoute returns a handler function for a route.
func (g *Gateway) handleRoute(route RouteConfig) gin.HandlerFunc {
	return func(c *gin.Context) {
		// TODO: Add authentication middleware if auth_required is true
		// TODO: Add rate limiting middleware
		// TODO: Add CORS middleware

		// Discover service instances
		ctx := c.Request.Context()
		instances, err := g.registry.Discover(ctx, route.Service)
		if err != nil {
			g.log.Error("Failed to discover service",
				logger.String("service", route.Service),
				logger.Error(err),
			)
			c.JSON(http.StatusServiceUnavailable, gin.H{
				"error": "Service unavailable",
			})
			return
		}

		if len(instances) == 0 {
			g.log.Warn("No instances found for service",
				logger.String("service", route.Service),
			)
			c.JSON(http.StatusServiceUnavailable, gin.H{
				"error": "Service unavailable",
			})
			return
		}

		// Use first healthy instance (load balancing can be added later)
		instance := instances[0]
		targetURL := fmt.Sprintf("http://%s:%d", instance.Address, instance.Port)

		// Create reverse proxy
		target, err := url.Parse(targetURL)
		if err != nil {
			g.log.Error("Failed to parse target URL",
				logger.String("url", targetURL),
				logger.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "Internal server error",
			})
			return
		}

		proxy := httputil.NewSingleHostReverseProxy(target)
		proxy.ServeHTTP(c.Writer, c.Request)
	}
}

// loadRoutes loads route configurations from config.
func loadRoutes(cfg config.ConfigProvider) []RouteConfig {
	// For now, return empty routes - will be loaded from config in future
	// This is a placeholder implementation
	return []RouteConfig{}
}
