package rest

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

	"github.com/explorer/backend/api/freshness"
	"github.com/explorer/backend/api/middleware"
	"github.com/explorer/backend/api/track1"
	"github.com/explorer/backend/api/track2"
	"github.com/explorer/backend/api/track3"
	"github.com/explorer/backend/api/track4"
	"github.com/explorer/backend/libs/go-rpc-gateway"
)

// SetupTrackRoutes sets up track-specific routes with proper middleware
func (s *Server) SetupTrackRoutes(mux *http.ServeMux, authMiddleware *middleware.AuthMiddleware) {
	// Initialize Track 1 (RPC Gateway) using reusable lib
	rpcURL := os.Getenv("RPC_URL")
	if rpcURL == "" {
		rpcURL = "http://localhost:8545"
	}

	var cache gateway.Cache
	if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
		if c, err := gateway.NewRedisCache(redisURL); err == nil {
			cache = c
		}
	}
	if cache == nil {
		cache = gateway.NewInMemoryCache()
	}

	rateLimitConfig := gateway.RateLimitConfig{
		RequestsPerSecond: 10,
		RequestsPerMinute: 100,
		BurstSize:         20,
	}
	var rateLimiter gateway.RateLimiter
	if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
		if rl, err := gateway.NewRedisRateLimiter(redisURL, rateLimitConfig); err == nil {
			rateLimiter = rl
		}
	}
	if rateLimiter == nil {
		rateLimiter = gateway.NewInMemoryRateLimiter(rateLimitConfig)
	}

	rpcGateway := gateway.NewRPCGateway(rpcURL, cache, rateLimiter)
	track1Server := track1.NewServer(rpcGateway, func(ctx context.Context) (*freshness.Snapshot, *freshness.SummaryCompleteness, *freshness.Sampling, *freshness.Diagnostics, error) {
		if s.db == nil {
			return nil, nil, nil, nil, nil
		}
		now := time.Now().UTC()
		snapshot, completeness, sampling, diagnostics, err := freshness.BuildSnapshot(
			ctx,
			s.chainID,
			s.db.QueryRow,
			func(ctx context.Context) (*freshness.Reference, error) {
				return freshness.ProbeChainHead(ctx, rpcURL)
			},
			now,
			nil,
			nil,
		)
		if err != nil {
			return nil, nil, nil, nil, err
		}
		return &snapshot, &completeness, &sampling, &diagnostics, nil
	})

	// Track 1 routes (public, optional auth)
	mux.HandleFunc("/api/v1/track1/blocks/latest", track1Server.HandleLatestBlocks)
	mux.HandleFunc("/api/v1/track1/txs/latest", track1Server.HandleLatestTransactions)
	mux.HandleFunc("/api/v1/track1/block/", track1Server.HandleBlockDetail)
	mux.HandleFunc("/api/v1/track1/tx/", track1Server.HandleTransactionDetail)
	mux.HandleFunc("/api/v1/track1/address/", track1Server.HandleAddressBalance)
	mux.HandleFunc("/api/v1/track1/bridge/status", track1Server.HandleBridgeStatus)
	mux.HandleFunc("/api/v1/mission-control/stream", track1Server.HandleMissionControlStream)
	mux.HandleFunc("/api/v1/mission-control/liquidity/token/", s.handleMissionControlLiquidityTokenPath)
	mux.HandleFunc("/api/v1/mission-control/bridge/trace", s.HandleMissionControlBridgeTrace)

	// Initialize Track 2 server
	track2Server := track2.NewServer(s.db, s.chainID)

	// Track 2 routes (require Track 2+)
	track2Middleware := authMiddleware.RequireTrack(2)

	// Track 2 route handlers with auth
	track2AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
		return authMiddleware.RequireAuth(track2Middleware(http.HandlerFunc(handler))).ServeHTTP
	}

	mux.HandleFunc("/api/v1/track2/search", track2AuthHandler(track2Server.HandleSearch))

	// Address routes - need to parse path
	mux.HandleFunc("/api/v1/track2/address/", track2AuthHandler(func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		parts := strings.Split(strings.TrimPrefix(path, "/api/v1/track2/address/"), "/")
		if len(parts) >= 2 {
			if parts[1] == "txs" {
				track2Server.HandleAddressTransactions(w, r)
				return
			} else if parts[1] == "tokens" {
				track2Server.HandleAddressTokens(w, r)
				return
			} else if parts[1] == "internal-txs" {
				track2Server.HandleInternalTransactions(w, r)
				return
			}
		}

		writeError(w, http.StatusBadRequest, "bad_request", "Invalid Track 2 address path")
	}))

	mux.HandleFunc("/api/v1/track2/token/", track2AuthHandler(track2Server.HandleTokenInfo))

	// Initialize Track 3 server
	track3Server := track3.NewServer(s.db, s.chainID)

	// Track 3 routes (require Track 3+)
	track3Middleware := authMiddleware.RequireTrack(3)
	track3AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
		return authMiddleware.RequireAuth(track3Middleware(http.HandlerFunc(handler))).ServeHTTP
	}

	mux.HandleFunc("/api/v1/track3/analytics/flows", track3AuthHandler(track3Server.HandleFlows))
	mux.HandleFunc("/api/v1/track3/analytics/bridge", track3AuthHandler(track3Server.HandleBridge))
	mux.HandleFunc("/api/v1/track3/analytics/token-distribution/", track3AuthHandler(track3Server.HandleTokenDistribution))
	mux.HandleFunc("/api/v1/track3/analytics/address-risk/", track3AuthHandler(track3Server.HandleAddressRisk))

	// Initialize Track 4 server
	track4Server := track4.NewServer(s.db, s.chainID)

	// Track 4 routes (require Track 4 + IP whitelist)
	track4Middleware := authMiddleware.RequireTrack(4)
	track4AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
		return authMiddleware.RequireAuth(track4Middleware(http.HandlerFunc(handler))).ServeHTTP
	}

	mux.HandleFunc("/api/v1/track4/operator/bridge/events", track4AuthHandler(track4Server.HandleBridgeEvents))
	mux.HandleFunc("/api/v1/track4/operator/validators", track4AuthHandler(track4Server.HandleValidators))
	mux.HandleFunc("/api/v1/track4/operator/contracts", track4AuthHandler(track4Server.HandleContracts))
	mux.HandleFunc("/api/v1/track4/operator/protocol-state", track4AuthHandler(track4Server.HandleProtocolState))
	mux.HandleFunc("/api/v1/track4/operator/run-script", track4AuthHandler(track4Server.HandleRunScript))
}
