package gateway

import (
	"net/http"

	"github.com/DeBrosOfficial/network/pkg/gateway/ctxkeys"
)

// Routes returns the http.Handler with all routes and middleware configured
func (g *Gateway) Routes() http.Handler {
	mux := http.NewServeMux()

	// root and v1 health/status
	mux.HandleFunc("/health", g.healthHandler)
	mux.HandleFunc("/status", g.statusHandler)
	mux.HandleFunc("/v1/health", g.healthHandler)
	mux.HandleFunc("/v1/version", g.versionHandler)
	mux.HandleFunc("/v1/status", g.statusHandler)
	// Schema-version contract (bug #214 audit follow-up): tenants can
	// self-check whether their gateway's required schema is applied.
	mux.HandleFunc("/v1/schema-status", g.handleSchemaStatus)

	// Internal ping for peer-to-peer health monitoring
	mux.HandleFunc("/v1/internal/ping", g.pingHandler)

	// TLS check endpoint for Caddy on-demand TLS
	mux.HandleFunc("/v1/internal/tls/check", g.tlsCheckHandler)

	// ACME DNS-01 challenge endpoints (for Caddy httpreq DNS provider)
	mux.HandleFunc("/v1/internal/acme/present", g.acmePresentHandler)
	mux.HandleFunc("/v1/internal/acme/cleanup", g.acmeCleanupHandler)

	// WireGuard peer exchange (internal, cluster-secret auth)
	if g.wireguardHandler != nil {
		mux.HandleFunc("/v1/internal/wg/peer", g.wireguardHandler.HandleRegisterPeer)
		mux.HandleFunc("/v1/internal/wg/peers", g.wireguardHandler.HandleListPeers)
		mux.HandleFunc("/v1/internal/wg/peer/remove", g.wireguardHandler.HandleRemovePeer)
	}

	// Node join endpoint (token-authenticated, no middleware auth needed)
	if g.joinHandler != nil {
		mux.HandleFunc("/v1/internal/join", g.joinHandler.HandleJoin)
	}

	// OramaOS node management (handler does its own auth)
	if g.enrollHandler != nil {
		mux.HandleFunc("/v1/node/enroll", g.enrollHandler.HandleEnroll)
		mux.HandleFunc("/v1/node/status", g.enrollHandler.HandleNodeStatus)
		mux.HandleFunc("/v1/node/command", g.enrollHandler.HandleNodeCommand)
		mux.HandleFunc("/v1/node/logs", g.enrollHandler.HandleNodeLogs)
		mux.HandleFunc("/v1/node/leave", g.enrollHandler.HandleNodeLeave)
	}

	// Namespace instance spawn/stop (internal, handler does its own auth)
	if g.spawnHandler != nil {
		mux.Handle("/v1/internal/namespace/spawn", g.spawnHandler)
	}

	// Namespace cluster repair (internal, handler does its own auth)
	mux.HandleFunc("/v1/internal/namespace/repair", g.namespaceClusterRepairHandler)

	// Namespace WebRTC enable/disable/status (internal, handler does its own auth)
	mux.HandleFunc("/v1/internal/namespace/webrtc/enable", g.namespaceWebRTCEnableHandler)
	mux.HandleFunc("/v1/internal/namespace/webrtc/disable", g.namespaceWebRTCDisableHandler)
	mux.HandleFunc("/v1/internal/namespace/webrtc/status", g.namespaceWebRTCStatusHandler)

	// Namespace WebRTC enable/disable/status (public, JWT/API key auth via middleware)
	mux.HandleFunc("/v1/namespace/webrtc/enable", g.namespaceWebRTCEnablePublicHandler)
	mux.HandleFunc("/v1/namespace/webrtc/disable", g.namespaceWebRTCDisablePublicHandler)
	mux.HandleFunc("/v1/namespace/webrtc/stealth/enable", func(w http.ResponseWriter, r *http.Request) {
		g.namespaceWebRTCStealthPublicHandler(w, r, true)
	})
	mux.HandleFunc("/v1/namespace/webrtc/stealth/disable", func(w http.ResponseWriter, r *http.Request) {
		g.namespaceWebRTCStealthPublicHandler(w, r, false)
	})
	mux.HandleFunc("/v1/namespace/webrtc/status", g.namespaceWebRTCStatusPublicHandler)

	// auth endpoints
	mux.HandleFunc("/v1/auth/jwks", g.authService.JWKSHandler)
	mux.HandleFunc("/.well-known/jwks.json", g.authService.JWKSHandler)
	if g.authHandlers != nil {
		mux.HandleFunc("/v1/auth/challenge", g.authHandlers.ChallengeHandler)
		mux.HandleFunc("/v1/auth/verify", g.authHandlers.VerifyHandler)
		// Issue JWT from API key; create or return API key for a wallet after verification
		mux.HandleFunc("/v1/auth/token", g.authHandlers.APIKeyToJWTHandler)
		mux.HandleFunc("/v1/auth/api-key", g.authHandlers.IssueAPIKeyHandler)
		mux.HandleFunc("/v1/auth/simple-key", g.authHandlers.SimpleAPIKeyHandler)
		mux.HandleFunc("/v1/auth/register", g.authHandlers.RegisterHandler)
		mux.HandleFunc("/v1/auth/refresh", g.authHandlers.RefreshHandler)
		mux.HandleFunc("/v1/auth/logout", g.authHandlers.LogoutHandler)
		mux.HandleFunc("/v1/auth/whoami", g.authHandlers.WhoamiHandler)
		// Phantom Solana auth (QR code + deep link)
		mux.HandleFunc("/v1/auth/phantom/session", g.authHandlers.PhantomSessionHandler)
		mux.HandleFunc("/v1/auth/phantom/session/", g.authHandlers.PhantomSessionStatusHandler)
		mux.HandleFunc("/v1/auth/phantom/complete", g.authHandlers.PhantomCompleteHandler)
	}

	// RQLite native backup/restore proxy (namespace auth via /v1/rqlite/ prefix)
	mux.HandleFunc("/v1/rqlite/export", g.rqliteExportHandler)
	mux.HandleFunc("/v1/rqlite/import", g.rqliteImportHandler)

	// rqlite ORM HTTP gateway (mounts /v1/rqlite/* endpoints)
	if g.ormHTTP != nil {
		g.ormHTTP.BasePath = "/v1/rqlite"
		g.ormHTTP.RegisterRoutes(mux)
	}

	// namespace cluster status (public endpoint for polling during provisioning)
	mux.HandleFunc("/v1/namespace/status", g.namespaceClusterStatusHandler)

	// namespace delete (authenticated — goes through auth middleware)
	if g.namespaceDeleteHandler != nil {
		mux.Handle("/v1/namespace/delete", g.namespaceDeleteHandler)
	}

	// namespace list (authenticated — lists namespaces owned by the current wallet)
	if g.namespaceListHandler != nil {
		mux.Handle("/v1/namespace/list", g.namespaceListHandler)
	}

	// network
	mux.HandleFunc("/v1/network/status", g.networkStatusHandler)
	mux.HandleFunc("/v1/network/peers", g.networkPeersHandler)
	mux.HandleFunc("/v1/network/connect", g.networkConnectHandler)
	mux.HandleFunc("/v1/network/disconnect", g.networkDisconnectHandler)

	// pubsub
	if g.pubsubHandlers != nil {
		mux.HandleFunc("/v1/pubsub/ws", g.pubsubHandlers.WebsocketHandler)
		mux.HandleFunc("/v1/pubsub/publish", g.pubsubHandlers.PublishHandler)
		mux.HandleFunc("/v1/pubsub/publish-batch", g.pubsubHandlers.PublishBatchHandler)
		mux.HandleFunc("/v1/pubsub/topics", g.pubsubHandlers.TopicsHandler)
		mux.HandleFunc("/v1/pubsub/presence", g.pubsubHandlers.PresenceHandler)
	}

	// push notifications
	//
	// Routes are ALWAYS registered (bug #220). When no provider is
	// configured, the handler returns a canonical 503 envelope explaining
	// that push isn't enabled — far better UX than a bare 404 that sends
	// operators down "is the gateway broken?" rabbit holes.
	mux.HandleFunc("/v1/push/devices", g.pushDevicesHandler)
	// DELETE /v1/push/devices/{id} — uses path-prefix routing because
	// net/http mux doesn't extract path params; the handler parses {id}.
	mux.HandleFunc("/v1/push/devices/", g.pushDevicesByIDHandler)
	mux.HandleFunc("/v1/push/send", g.pushSendHandler)

	// Per-namespace push provider configuration (bug #220 follow-up):
	// GET / PUT / DELETE — tenants self-serve their ntfy/expo credentials
	// instead of filing an ops ticket. Method dispatched in the handler.
	mux.HandleFunc("/v1/push/config", g.pushConfigHandler)

	// Per-namespace, per-provider push credentials (feature #72 —
	// full-privacy push with APNs-direct + self-hosted ntfy). Generic by
	// design: any provider with a registered Validator plugs in here
	// without changes. Method + provider segment dispatched in the handler.
	//
	// Summary endpoint (no provider segment) returns "what's configured"
	// + "what's supported" in one round trip.
	mux.HandleFunc("/v1/namespace/push-credentials", g.pushCredentialsSummaryHandler)
	mux.HandleFunc("/v1/namespace/push-credentials/", g.pushCredentialsByProviderHandler)

	// Per-namespace rate-limit configuration (feature #69).
	// GET / PUT / DELETE — tenants self-serve their gateway-level rate
	// limit override (requests_per_minute, burst) up to an operator-set
	// ceiling. Falls back to gateway YAML defaults when no override is set.
	if g.rateLimitHandlers != nil {
		mux.HandleFunc("/v1/namespace/rate-limit", g.rateLimitConfigDispatcher)
	}

	// operator node management (wallet JWT auth via middleware)
	if g.operatorHandler != nil {
		mux.HandleFunc("/v1/operator/invite", g.operatorHandler.HandleInvite)
		mux.HandleFunc("/v1/operator/nodes", g.operatorHandler.HandleListNodes)
		mux.HandleFunc("/v1/operator/node/register", g.operatorHandler.HandleRegister)
	}

	// vault proxy (public, rate-limited per identity within handler)
	if g.vaultHandlers != nil {
		mux.HandleFunc("/v1/vault/push", g.vaultHandlers.HandlePush)
		mux.HandleFunc("/v1/vault/pull", g.vaultHandlers.HandlePull)
		mux.HandleFunc("/v1/vault/health", g.vaultHandlers.HandleHealth)
		mux.HandleFunc("/v1/vault/status", g.vaultHandlers.HandleStatus)
	}

	// webrtc — TURN credentials and SFU signaling are gated independently
	// (bugboard #25). A non-SFU gateway with the namespace TURN secret
	// serves credentials but not signal/rooms; an SFU gateway serves all.
	if g.webrtcHandlers != nil {
		if g.webrtcServeTURNCredentials {
			mux.HandleFunc("/v1/webrtc/turn/credentials", g.webrtcHandlers.CredentialsHandler)
		}
		if g.webrtcServeSFURoutes {
			mux.HandleFunc("/v1/webrtc/signal", g.webrtcHandlers.SignalHandler)
			mux.HandleFunc("/v1/webrtc/rooms", g.webrtcHandlers.RoomsHandler)
		}
	}

	// anon proxy (authenticated users only)
	mux.HandleFunc("/v1/proxy/anon", g.anonProxyHandler)

	// cache endpoints (Olric) - always register, check handler dynamically
	// This allows cache routes to work after background Olric reconnection
	mux.HandleFunc("/v1/cache/health", g.cacheHealthHandler)
	mux.HandleFunc("/v1/cache/get", g.cacheGetHandler)
	mux.HandleFunc("/v1/cache/mget", g.cacheMGetHandler)
	mux.HandleFunc("/v1/cache/put", g.cachePutHandler)
	mux.HandleFunc("/v1/cache/delete", g.cacheDeleteHandler)
	mux.HandleFunc("/v1/cache/scan", g.cacheScanHandler)

	// storage endpoints (IPFS)
	if g.storageHandlers != nil {
		mux.HandleFunc("/v1/storage/upload", g.storageHandlers.UploadHandler)
		mux.HandleFunc("/v1/storage/pin", g.storageHandlers.PinHandler)
		mux.HandleFunc("/v1/storage/status/", g.storageHandlers.StatusHandler)
		mux.HandleFunc("/v1/storage/get/", g.storageHandlers.DownloadHandler)
		mux.HandleFunc("/v1/storage/unpin/", g.storageHandlers.UnpinHandler)
	}

	// serverless functions (if enabled)
	if g.serverlessHandlers != nil {
		g.serverlessHandlers.RegisterRoutes(mux)
	}

	// deployment endpoints
	if g.deploymentService != nil {
		// Static deployments
		mux.HandleFunc("/v1/deployments/static/upload", g.staticHandler.HandleUpload)
		mux.HandleFunc("/v1/deployments/static/update", g.withHomeNodeProxy(g.updateHandler.HandleUpdate))

		// Next.js deployments
		mux.HandleFunc("/v1/deployments/nextjs/upload", g.nextjsHandler.HandleUpload)
		mux.HandleFunc("/v1/deployments/nextjs/update", g.withHomeNodeProxy(g.updateHandler.HandleUpdate))

		// Go backend deployments
		if g.goHandler != nil {
			mux.HandleFunc("/v1/deployments/go/upload", g.goHandler.HandleUpload)
			mux.HandleFunc("/v1/deployments/go/update", g.withHomeNodeProxy(g.updateHandler.HandleUpdate))
		}

		// Node.js backend deployments
		if g.nodejsHandler != nil {
			mux.HandleFunc("/v1/deployments/nodejs/upload", g.nodejsHandler.HandleUpload)
			mux.HandleFunc("/v1/deployments/nodejs/update", g.withHomeNodeProxy(g.updateHandler.HandleUpdate))
		}

		// Deployment management
		mux.HandleFunc("/v1/deployments/list", g.listHandler.HandleList)
		mux.HandleFunc("/v1/deployments/get", g.listHandler.HandleGet)
		mux.HandleFunc("/v1/deployments/delete", g.withHomeNodeProxy(g.listHandler.HandleDelete))
		mux.HandleFunc("/v1/deployments/rollback", g.withHomeNodeProxy(g.rollbackHandler.HandleRollback))
		mux.HandleFunc("/v1/deployments/versions", g.rollbackHandler.HandleListVersions)
		mux.HandleFunc("/v1/deployments/logs", g.withHomeNodeProxy(g.logsHandler.HandleLogs))
		mux.HandleFunc("/v1/deployments/stats", g.withHomeNodeProxy(g.statsHandler.HandleStats))
		mux.HandleFunc("/v1/deployments/events", g.logsHandler.HandleGetEvents)

		// Internal replica coordination endpoints
		if g.replicaHandler != nil {
			mux.HandleFunc("/v1/internal/deployments/replica/setup", g.replicaHandler.HandleSetup)
			mux.HandleFunc("/v1/internal/deployments/replica/update", g.replicaHandler.HandleUpdate)
			mux.HandleFunc("/v1/internal/deployments/replica/rollback", g.replicaHandler.HandleRollback)
			mux.HandleFunc("/v1/internal/deployments/replica/teardown", g.replicaHandler.HandleTeardown)
		}

		// Custom domains
		mux.HandleFunc("/v1/deployments/domains/add", g.domainHandler.HandleAddDomain)
		mux.HandleFunc("/v1/deployments/domains/verify", g.domainHandler.HandleVerifyDomain)
		mux.HandleFunc("/v1/deployments/domains/list", g.domainHandler.HandleListDomains)
		mux.HandleFunc("/v1/deployments/domains/remove", g.domainHandler.HandleRemoveDomain)
	}

	// SQLite database endpoints
	if g.sqliteHandler != nil {
		mux.HandleFunc("/v1/db/sqlite/create", g.sqliteHandler.CreateDatabase)
		mux.HandleFunc("/v1/db/sqlite/query", g.sqliteHandler.QueryDatabase)
		mux.HandleFunc("/v1/db/sqlite/list", g.sqliteHandler.ListDatabases)
		mux.HandleFunc("/v1/db/sqlite/backup", g.sqliteBackupHandler.BackupDatabase)
		mux.HandleFunc("/v1/db/sqlite/backups", g.sqliteBackupHandler.ListBackups)
	}

	return g.withMiddleware(mux)
}

// withHomeNodeProxy wraps a deployment handler to proxy requests to the home node
// if the current node is not the home node for the deployment.
func (g *Gateway) withHomeNodeProxy(handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Already proxied — prevent loops
		if r.Header.Get("X-Orama-Proxy-Node") != "" {
			handler(w, r)
			return
		}
		name := r.URL.Query().Get("name")
		if name == "" {
			handler(w, r)
			return
		}
		ctx := r.Context()
		namespace, _ := ctx.Value(ctxkeys.NamespaceOverride).(string)
		if namespace == "" {
			handler(w, r)
			return
		}
		deployment, err := g.deploymentService.GetDeployment(ctx, namespace, name)
		if err != nil {
			handler(w, r) // let handler return proper error
			return
		}
		if g.nodePeerID != "" && deployment.HomeNodeID != "" &&
			deployment.HomeNodeID != g.nodePeerID {
			if g.proxyCrossNode(w, r, deployment) {
				return
			}
		}
		handler(w, r)
	}
}
