package router

import (
	"context"
	"log/slog"
	"net/http"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/jackc/pgx/v5/pgxpool"

	"github.com/denisovdennis/autohero/internal/game"
	"github.com/denisovdennis/autohero/internal/handler"
	"github.com/denisovdennis/autohero/internal/storage"
	"github.com/denisovdennis/autohero/internal/world"
)

// Deps holds all dependencies needed by the router.
type Deps struct {
	Engine                 *game.Engine
	Hub                    *handler.Hub
	PgPool                 *pgxpool.Pool
	BotToken               string
	PaymentProviderToken   string
	AdminBasicAuthUsername string
	AdminBasicAuthPassword string
	AdminBasicAuthRealm    string
	Logger                 *slog.Logger
	ServerStartedAt        time.Time
}

// New creates the chi router with all routes wired.
func New(deps Deps) *chi.Mux {
	r := chi.NewRouter()

	// Middleware stack.
	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Recoverer)
	r.Use(middleware.Heartbeat("/ping"))
	r.Use(corsMiddleware)

	// Health.
	healthH := handler.NewHealthHandler()
	r.Get("/health", healthH.Health)

	// Stores (PostgreSQL-backed persistence).
	heroStore := storage.NewHeroStore(deps.PgPool, deps.Logger)

	// WebSocket (needs heroStore to resolve telegram ID → hero DB ID).
	wsH := handler.NewWSHandler(deps.Hub, heroStore, deps.Logger)
	r.Get("/ws", wsH.HandleWS)
	logStore := storage.NewLogStore(deps.PgPool)
	questStore := storage.NewQuestStore(deps.PgPool)
	gearStore := storage.NewGearStore(deps.PgPool)
	achievementStore := storage.NewAchievementStore(deps.PgPool)
	taskStore := storage.NewDailyTaskStore(deps.PgPool)
	worldSvc := world.NewService()

	// Auth endpoint (no auth middleware required - this IS the auth).
	authH := handler.NewAuthHandler(deps.BotToken, heroStore, deps.Logger)
	r.Post("/api/v1/auth/telegram", authH.TelegramAuth)

	// Telegram Payments.
	paymentsH := handler.NewPaymentsHandler(deps.BotToken, deps.PaymentProviderToken, heroStore, logStore, deps.Logger)
	r.Post("/api/v1/payments/create-invoice", paymentsH.CreateInvoice)
	r.Post("/api/v1/payments/telegram-webhook", paymentsH.TelegramWebhook)

	// Admin routes protected with HTTP Basic authentication.
	adminH := handler.NewAdminHandler(heroStore, gearStore, questStore, deps.Engine, deps.Hub, deps.PgPool, deps.Logger)
	r.Route("/admin", func(r chi.Router) {
		r.Use(handler.BasicAuthMiddleware(handler.BasicAuthConfig{
			Username: deps.AdminBasicAuthUsername,
			Password: deps.AdminBasicAuthPassword,
			Realm:    deps.AdminBasicAuthRealm,
		}))
		r.Get("/heroes", adminH.ListHeroes)
		r.Get("/heroes/{heroId}", adminH.GetHero)
		r.Post("/heroes/{heroId}/set-level", adminH.SetHeroLevel)
		r.Post("/heroes/{heroId}/set-gold", adminH.SetHeroGold)
		r.Post("/heroes/{heroId}/set-hp", adminH.SetHeroHP)
		r.Post("/heroes/{heroId}/add-potions", adminH.AddPotions)
		r.Post("/heroes/{heroId}/revive", adminH.ReviveHero)
		r.Post("/heroes/{heroId}/reset", adminH.ResetHero)
		r.Post("/heroes/{heroId}/reset-buff-charges", adminH.ResetBuffCharges)
		r.Post("/heroes/{heroId}/teleport-town", adminH.TeleportHeroTown)
		r.Post("/heroes/{heroId}/start-rest", adminH.StartHeroRest)
		r.Post("/heroes/{heroId}/start-roadside-rest", adminH.StartHeroRoadsideRest)
		r.Post("/heroes/{heroId}/start-adventure", adminH.StartHeroExcursion)
		r.Post("/heroes/{heroId}/stop-adventure", adminH.StopHeroExcursion)
		r.Post("/heroes/{heroId}/stop-rest", adminH.StopHeroRest)
		r.Post("/heroes/{heroId}/leave-town", adminH.ForceLeaveTown)
		r.Get("/heroes/{heroId}/gear", adminH.GetHeroGear)
		r.Post("/heroes/{heroId}/gear/grant", adminH.GrantHeroGear)
		r.Post("/heroes/{heroId}/gear/equip", adminH.EquipHeroGear)
		r.Post("/heroes/{heroId}/gear/unequip", adminH.UnequipHeroGear)
		r.Delete("/heroes/{heroId}/gear/{itemId}", adminH.DeleteHeroGear)
		r.Get("/heroes/{heroId}/quests", adminH.GetHeroQuests)
		r.Post("/heroes/{heroId}/quests/{questId}/accept", adminH.AcceptHeroQuest)
		r.Post("/heroes/{heroId}/quests/{questId}/claim", adminH.ClaimHeroQuest)
		r.Delete("/heroes/{heroId}/quests/{questId}", adminH.AbandonHeroQuest)
		r.Get("/gear/catalog", adminH.GearCatalog)
		r.Get("/content/quests", adminH.ContentAllQuests)
		r.Post("/content/quests", adminH.ContentCreateQuest)
		r.Put("/content/quests/{questId}", adminH.ContentUpdateQuest)
		r.Get("/content/gear-base", adminH.ContentGearBase)
		r.Post("/content/gear", adminH.ContentCreateGear)
		r.Put("/content/gear/{gearId}", adminH.ContentUpdateGear)
		r.Get("/quests/towns", adminH.ListTownsForQuests)
		r.Get("/quests/towns/{townId}/npcs", adminH.ListTownNPCsForQuests)
		r.Get("/quests/npcs/{npcId}", adminH.ListNPCQuestsForAdmin)
		r.Delete("/heroes/{heroId}", adminH.DeleteHero)
		r.Get("/towns", adminH.ListTowns)
		r.Post("/time/pause", adminH.PauseTime)
		r.Post("/time/resume", adminH.ResumeTime)
		r.Get("/engine/status", adminH.EngineStatus)
		r.Get("/engine/combats", adminH.ActiveCombats)
		r.Get("/ws/connections", adminH.WSConnections)
		r.Get("/info", adminH.ServerInfo)
		r.Get("/runtime-config", adminH.GetRuntimeConfig)
		r.Post("/runtime-config", adminH.UpdateRuntimeConfig)
		r.Post("/runtime-config/reload", adminH.ReloadRuntimeConfig)
		r.Get("/buff-debuff-config", adminH.GetBuffDebuffConfig)
		r.Post("/buff-debuff-config", adminH.UpdateBuffDebuffConfig)
		r.Post("/buff-debuff-config/reload", adminH.ReloadBuffDebuffConfig)
		r.Get("/payments", adminH.ListPayments)
		r.Get("/payments/{paymentId}", adminH.GetPayment)
		r.Post("/payments/set-webhook", paymentsH.SetWebhook)
	})

	// API v1 (authenticated routes).
	gameH := handler.NewGameHandler(deps.Engine, heroStore, logStore, worldSvc, deps.Logger, deps.ServerStartedAt, questStore, gearStore, achievementStore, taskStore, deps.Hub)
	mapsH := handler.NewMapsHandler(worldSvc, deps.Logger)
	questH := handler.NewQuestHandler(questStore, heroStore, logStore, deps.Logger)
	npcH := handler.NewNPCHandler(questStore, heroStore, gearStore, logStore, deps.Logger, deps.Engine, deps.Hub)
	deps.Engine.SetNPCAlmsHandler(func(ctx context.Context, heroID int64) error {
		return npcH.ProcessAlmsByHeroID(ctx, heroID)
	})
	achieveH := handler.NewAchievementHandler(achievementStore, heroStore, deps.Logger)
	taskH := handler.NewDailyTaskHandler(taskStore, heroStore, deps.Logger)
	r.Route("/api/v1", func(r chi.Router) {
		// Apply Telegram auth middleware to all routes in this group.
		// Disabled for now to allow development without a bot token.
		// r.Use(handler.TelegramAuthMiddleware(deps.BotToken))

		r.Use(handler.APITimePausedMiddleware(deps.Engine))

		r.Get("/hero", gameH.GetHero)
		r.Get("/hero/init", gameH.InitHero)
		r.Post("/hero/name", gameH.SetHeroName)
		r.Post("/hero/buff/{buffType}", gameH.ActivateBuff)
		r.Post("/hero/encounter", gameH.RequestEncounter)
		r.Post("/hero/victory", gameH.ReportVictory)
		r.Post("/hero/revive", gameH.ReviveHero)
		r.Post("/hero/purchase-buff-refill", gameH.PurchaseBuffRefill)
		r.Post("/hero/purchase-subscription", gameH.PurchaseSubscription)
		r.Get("/hero/loot", gameH.GetLoot)
		r.Get("/hero/log", gameH.GetAdventureLog)
		r.Post("/hero/use-potion", gameH.UsePotion)
		r.Get("/weapons", gameH.GetWeapons)
		r.Get("/armor", gameH.GetArmor)
		r.Get("/maps/{mapId}", mapsH.GetMap)

		// Quest system routes.
		r.Get("/towns", questH.ListTowns)
		r.Get("/towns/{townId}/npcs", questH.ListNPCsByTown)
		r.Get("/towns/{townId}/buildings", questH.ListBuildingsByTown)
		r.Get("/npcs/{npcId}/quests", questH.ListQuestsByNPC)
		r.Post("/hero/quests/{questId}/accept", questH.AcceptQuest)
		r.Get("/hero/quests", questH.ListHeroQuests)
		r.Post("/hero/quests/{questId}/claim", questH.ClaimQuestReward)
		r.Delete("/hero/quests/{questId}", questH.AbandonQuest)

		// NPC interaction routes.
		r.Post("/hero/npc-interact", npcH.InteractNPC)
		r.Get("/hero/nearby-npcs", npcH.NearbyNPCs)
		r.Post("/hero/npc-alms", npcH.NPCAlms)
		r.Post("/hero/npc-heal", npcH.HealHero)
		r.Post("/hero/npc-buy-potion", npcH.BuyPotion)

		// Gear routes.
		r.Get("/hero/gear", gameH.GetHeroGear)
		r.Get("/hero/equipment", gameH.GetHeroGear) // backward compat
		r.Get("/gear/catalog", gameH.GetGearCatalog)

		// Achievement routes.
		r.Get("/hero/achievements", achieveH.GetHeroAchievements)

		// Daily/weekly task routes.
		r.Get("/hero/tasks", taskH.ListHeroTasks)
		r.Post("/hero/tasks/{taskId}/claim", taskH.ClaimTask)

		// Shared world routes.
		r.Get("/hero/nearby", gameH.NearbyHeroes)
	})

	return r
}

// corsMiddleware adds CORS headers to all responses.
func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Telegram-Init-Data")
		w.Header().Set("Access-Control-Max-Age", "86400")

		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		next.ServeHTTP(w, r)
	})
}
