package httproutes

import (
	"net/http"

	"hyapp/services/gateway-service/internal/transport/http/httpkit"
)

const APIV1Prefix = "/api/v1"

type Wrapper func(http.HandlerFunc) http.Handler

type Config struct {
	PublicWrap  Wrapper
	AuthWrap    Wrapper
	ProfileWrap Wrapper
	Auth        AuthHandlers
	App         AppHandlers
	User        UserHandlers
	Manager     ManagerHandlers
	Room        RoomHandlers
	Message     MessageHandlers
	Task        TaskHandlers
	Wallet      WalletHandlers
	VIP         VIPHandlers
	Game        GameHandlers
}

type AuthHandlers struct {
	LoginPassword   http.HandlerFunc
	SetPassword     http.HandlerFunc
	LoginThirdParty http.HandlerFunc
	RefreshToken    http.HandlerFunc
	Logout          http.HandlerFunc
}

type AppHandlers struct {
	ListRegistrationCountries http.HandlerFunc
	GetAppBootstrap           http.HandlerFunc
	ListH5Links               http.HandlerFunc
	ListAppBanners            http.HandlerFunc
	GetAppVersion             http.HandlerFunc
	ListResources             http.HandlerFunc
	GetResourceGroup          http.HandlerFunc
	ListGifts                 http.HandlerFunc
	IssueTencentIMUserSig     http.HandlerFunc
	IssueTencentRTCToken      http.HandlerFunc
	HandleTencentIMCallback   http.HandlerFunc
	HandleTencentRTCCallback  http.HandlerFunc
	UploadFile                http.HandlerFunc
	UploadAvatar              http.HandlerFunc
	HandlePushToken           http.HandlerFunc
}

type UserHandlers struct {
	ResolveDisplayUserID       http.HandlerFunc
	BatchUserProfiles          http.HandlerFunc
	BatchRoomDisplayProfiles   http.HandlerFunc
	GetMyOverview              http.HandlerFunc
	GetMyIdentity              http.HandlerFunc
	GetMyHostIdentity          http.HandlerFunc
	GetMyRoleSummary           http.HandlerFunc
	CompleteMyOnboarding       http.HandlerFunc
	UpdateMyProfile            http.HandlerFunc
	ChangeMyCountry            http.HandlerFunc
	ChangeMyDisplayUserID      http.HandlerFunc
	ApplyMyPrettyDisplayUserID http.HandlerFunc
	ListMyProfileVisitors      http.HandlerFunc
	ListMyFollowing            http.HandlerFunc
	ListMyFriends              http.HandlerFunc
	ListMyFriendApplications   http.HandlerFunc
	GetMyProfile               http.HandlerFunc
	ListMyResources            http.HandlerFunc
	EquipMyResource            http.HandlerFunc
	UserSocialAction           http.HandlerFunc
}

type ManagerHandlers struct {
	ListManagerGrantResources http.HandlerFunc
	GrantManagerResource      http.HandlerFunc
	LookupBusinessUsers       http.HandlerFunc
}

type RoomHandlers struct {
	GetMyRoom            http.HandlerFunc
	ListRoomFeeds        http.HandlerFunc
	ListRooms            http.HandlerFunc
	GetCurrentRoom       http.HandlerFunc
	GetRoomSnapshot      http.HandlerFunc
	GetRoomDetail        http.HandlerFunc
	ListRoomOnlineUsers  http.HandlerFunc
	GetRoomGiftPanel     http.HandlerFunc
	CreateRoom           http.HandlerFunc
	UpdateRoomProfile    http.HandlerFunc
	JoinRoom             http.HandlerFunc
	RoomHeartbeat        http.HandlerFunc
	LeaveRoom            http.HandlerFunc
	CloseRoom            http.HandlerFunc
	MicUp                http.HandlerFunc
	MicDown              http.HandlerFunc
	ChangeMicSeat        http.HandlerFunc
	ConfirmMicPublishing http.HandlerFunc
	SetMicMute           http.HandlerFunc
	SetMicSeatLock       http.HandlerFunc
	SetChatEnabled       http.HandlerFunc
	SetRoomAdmin         http.HandlerFunc
	MuteUser             http.HandlerFunc
	KickUser             http.HandlerFunc
	UnbanUser            http.HandlerFunc
	SendGift             http.HandlerFunc
}

type MessageHandlers struct {
	ListMessageTabs          http.HandlerFunc
	MarkInboxSectionRead     http.HandlerFunc
	MarkInboxMessageReadPath http.HandlerFunc
	DeleteInboxMessagePath   http.HandlerFunc
	ListInboxMessages        http.HandlerFunc
}

type TaskHandlers struct {
	ListTaskTabs                     http.HandlerFunc
	ClaimTaskReward                  http.HandlerFunc
	GetRegistrationRewardEligibility http.HandlerFunc
}

type WalletHandlers struct {
	GetWalletOverview        http.HandlerFunc
	GetMyBalances            http.HandlerFunc
	ListRechargeProducts     http.HandlerFunc
	GetDiamondExchangeConfig http.HandlerFunc
	ApplyWithdrawal          http.HandlerFunc
	ListCoinTransactions     http.HandlerFunc
	ListWalletTransactions   http.HandlerFunc
	TransferCoinFromSeller   http.HandlerFunc
}

type VIPHandlers struct {
	GetMyVIP        http.HandlerFunc
	ListVIPPackages http.HandlerFunc
	PurchaseVIP     http.HandlerFunc
}

type GameHandlers struct {
	ListGames      http.HandlerFunc
	LaunchGame     http.HandlerFunc
	HandleCallback http.HandlerFunc
}

type routes struct {
	mux    *http.ServeMux
	config Config
}

// New 只维护 gateway 对外 HTTP 路径到 transport handler 的绑定。
// 业务状态和命令执行仍然全部下沉到 owner service，路由层不承载业务规则。
func New(config Config) http.Handler {
	mux := http.NewServeMux()
	routes := routes{mux: mux, config: config}

	routes.registerAuthRoutes()
	routes.registerAppRoutes()
	routes.registerUserRoutes()
	routes.registerManagerRoutes()
	routes.registerRoomRoutes()
	routes.registerMessageRoutes()
	routes.registerTaskRoutes()
	routes.registerWalletRoutes()
	routes.registerVIPRoutes()
	routes.registerGameRoutes()

	return mux
}

func (r routes) public(path string, method string, next http.HandlerFunc) {
	r.register(path, method, r.config.PublicWrap, next)
}

func (r routes) auth(path string, method string, next http.HandlerFunc) {
	r.register(path, method, r.config.AuthWrap, next)
}

func (r routes) profile(path string, method string, next http.HandlerFunc) {
	r.register(path, method, r.config.ProfileWrap, next)
}

func (r routes) register(path string, method string, wrap Wrapper, next http.HandlerFunc) {
	if method != "" {
		// method 继续走 gateway envelope，而不是使用 ServeMux 自动 405。
		next = httpkit.RequireMethod(method, next)
	}
	r.mux.Handle(APIV1Prefix+path, wrap(next))
}

func (r routes) registerAuthRoutes() {
	h := r.config.Auth
	r.public("/auth/account/login", "", h.LoginPassword)
	r.auth("/auth/password/set", "", h.SetPassword)
	r.public("/auth/third-party/login", "", h.LoginThirdParty)
	r.public("/auth/token/refresh", "", h.RefreshToken)
	r.public("/auth/logout", "", h.Logout)
}

func (r routes) registerAppRoutes() {
	h := r.config.App
	r.public("/countries", "", h.ListRegistrationCountries)
	r.public("/app/bootstrap", "", h.GetAppBootstrap)
	r.public("/app/h5-links", "", h.ListH5Links)
	r.public("/app/banners", "", h.ListAppBanners)
	r.public("/app/version", http.MethodGet, h.GetAppVersion)
	r.public("/resources", "", h.ListResources)
	r.public("/resource-groups/{group_id}", "", h.GetResourceGroup)
	r.public("/gifts", "", h.ListGifts)
	r.profile("/im/usersig", http.MethodGet, h.IssueTencentIMUserSig)
	r.profile("/rtc/token", http.MethodPost, h.IssueTencentRTCToken)
	r.public("/tencent-im/callback", "", h.HandleTencentIMCallback)
	r.public("/tencent-rtc/callback", "", h.HandleTencentRTCCallback)
	r.auth("/files/upload", "", h.UploadFile)
	r.auth("/files/avatar/upload", "", h.UploadAvatar)
	r.profile("/devices/push-token", "", h.HandlePushToken)
}

func (r routes) registerUserRoutes() {
	h := r.config.User
	r.public("/users/by-display-user-id/{display_user_id}", "", h.ResolveDisplayUserID)
	r.profile("/users/profiles:batch", "", h.BatchUserProfiles)
	r.profile("/users/room-display-profiles:batch", http.MethodGet, h.BatchRoomDisplayProfiles)
	r.profile("/users/me/overview", "", h.GetMyOverview)
	r.auth("/users/me/identity", "", h.GetMyIdentity)
	r.profile("/users/me/host-identity", "", h.GetMyHostIdentity)
	r.profile("/users/me/role-summary", "", h.GetMyRoleSummary)
	r.auth("/users/me/onboarding/complete", "", h.CompleteMyOnboarding)
	r.profile("/users/me/profile/update", "", h.UpdateMyProfile)
	r.profile("/users/me/country/change", "", h.ChangeMyCountry)
	r.auth("/users/me/display-id/change", "", h.ChangeMyDisplayUserID)
	r.auth("/users/me/display-id/pretty/apply", "", h.ApplyMyPrettyDisplayUserID)
	r.profile("/users/me/visitors", http.MethodGet, h.ListMyProfileVisitors)
	r.profile("/users/me/following", http.MethodGet, h.ListMyFollowing)
	r.profile("/users/me/friends", http.MethodGet, h.ListMyFriends)
	r.profile("/users/me/friend-requests", http.MethodGet, h.ListMyFriendApplications)
	r.profile("/users/me", "", h.GetMyProfile)
	r.profile("/users/me/resources", "", h.ListMyResources)
	r.profile("/users/me/resources/{resource_id}/equip", "", h.EquipMyResource)
	r.profile("/users/{user_id}/{action...}", "", h.UserSocialAction)
}

func (r routes) registerManagerRoutes() {
	h := r.config.Manager
	r.profile("/manager-center/resource-grants/resources", http.MethodGet, h.ListManagerGrantResources)
	r.profile("/manager-center/resource-grants", http.MethodPost, h.GrantManagerResource)
	r.profile("/business/users/lookup", http.MethodGet, h.LookupBusinessUsers)
}

func (r routes) registerRoomRoutes() {
	h := r.config.Room
	r.profile("/rooms/me", http.MethodGet, h.GetMyRoom)
	r.profile("/rooms/feeds", http.MethodGet, h.ListRoomFeeds)
	r.profile("/rooms", http.MethodGet, h.ListRooms)
	r.profile("/rooms/current", http.MethodGet, h.GetCurrentRoom)
	r.profile("/rooms/snapshot", http.MethodGet, h.GetRoomSnapshot)
	r.profile("/rooms/{room_id}/detail", http.MethodGet, h.GetRoomDetail)
	r.profile("/rooms/{room_id}/online-users", http.MethodGet, h.ListRoomOnlineUsers)
	r.profile("/rooms/{room_id}/gift-panel", http.MethodGet, h.GetRoomGiftPanel)
	r.profile("/rooms/create", http.MethodPost, h.CreateRoom)
	r.profile("/rooms/profile/update", http.MethodPost, h.UpdateRoomProfile)
	r.profile("/rooms/join", http.MethodPost, h.JoinRoom)
	r.profile("/rooms/heartbeat", http.MethodPost, h.RoomHeartbeat)
	r.profile("/rooms/leave", http.MethodPost, h.LeaveRoom)
	r.profile("/rooms/close", http.MethodPost, h.CloseRoom)
	r.profile("/rooms/mic/up", http.MethodPost, h.MicUp)
	r.profile("/rooms/mic/down", http.MethodPost, h.MicDown)
	r.profile("/rooms/mic/change", http.MethodPost, h.ChangeMicSeat)
	r.profile("/rooms/mic/publishing/confirm", http.MethodPost, h.ConfirmMicPublishing)
	r.profile("/rooms/mic/mute", http.MethodPost, h.SetMicMute)
	r.profile("/rooms/mic/lock", http.MethodPost, h.SetMicSeatLock)
	r.profile("/rooms/chat/enabled", http.MethodPost, h.SetChatEnabled)
	r.profile("/rooms/admin/set", http.MethodPost, h.SetRoomAdmin)
	r.profile("/rooms/user/mute", http.MethodPost, h.MuteUser)
	r.profile("/rooms/user/kick", http.MethodPost, h.KickUser)
	r.profile("/rooms/user/unban", http.MethodPost, h.UnbanUser)
	r.profile("/rooms/gift/send", http.MethodPost, h.SendGift)
}

func (r routes) registerMessageRoutes() {
	h := r.config.Message
	r.profile("/messages/tabs", "", h.ListMessageTabs)
	r.profile("/messages/read-all", "", h.MarkInboxSectionRead)
	r.profile("/messages/{message_id}/read", "", h.MarkInboxMessageReadPath)
	r.profile("/messages/{message_id}", "", h.DeleteInboxMessagePath)
	r.profile("/messages", "", h.ListInboxMessages)
}

func (r routes) registerTaskRoutes() {
	h := r.config.Task
	r.profile("/activities/registration-reward/eligibility", http.MethodGet, h.GetRegistrationRewardEligibility)
	r.profile("/tasks/tabs", http.MethodGet, h.ListTaskTabs)
	r.profile("/tasks/claim", http.MethodPost, h.ClaimTaskReward)
}

func (r routes) registerWalletRoutes() {
	h := r.config.Wallet
	r.profile("/wallet/me/overview", http.MethodGet, h.GetWalletOverview)
	r.profile("/wallet/me/balances", "", h.GetMyBalances)
	r.profile("/wallet/recharge/products", http.MethodGet, h.ListRechargeProducts)
	r.profile("/wallet/diamond-exchange/config", http.MethodGet, h.GetDiamondExchangeConfig)
	r.profile("/wallet/withdrawals/apply", http.MethodPost, h.ApplyWithdrawal)
	r.profile("/wallet/coin-transactions", http.MethodGet, h.ListCoinTransactions)
	r.profile("/wallet/transactions", http.MethodGet, h.ListWalletTransactions)
	r.profile("/wallet/coin-seller/transfer", "", h.TransferCoinFromSeller)
}

func (r routes) registerVIPRoutes() {
	h := r.config.VIP
	r.profile("/vip/me", http.MethodGet, h.GetMyVIP)
	r.profile("/vip/packages", http.MethodGet, h.ListVIPPackages)
	r.profile("/vip/purchase", http.MethodPost, h.PurchaseVIP)
}

func (r routes) registerGameRoutes() {
	h := r.config.Game
	r.profile("/games", http.MethodGet, h.ListGames)
	r.profile("/games/{game_id}/launch", http.MethodPost, h.LaunchGame)
	r.public("/game-callbacks/{platform_code}/{operation}", http.MethodPost, h.HandleCallback)
}
