package main

import (
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"xboard-go/internal/config"
	"xboard-go/internal/database"
	"xboard-go/internal/handler"
	"xboard-go/internal/middleware"
	"xboard-go/internal/service"

	"github.com/gin-gonic/gin"
)

func main() {
	config.LoadConfig()
	configureRuntimeLogging()
	database.InitDB()
	database.InitCache()

	router := gin.New()
	if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
		router.Use(gin.Logger())
	}
	router.Use(gin.Recovery())

	api := router.Group("/api")
	registerV1(api.Group("/v1"))
	registerV2(api.Group("/v2"))
	registerWebRoutes(router)

	if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
		log.Printf("server starting on port %s (log_level: %s)", config.AppConfig.AppPort, config.AppConfig.LogLevel)
	}
	if err := router.Run(":" + config.AppConfig.AppPort); err != nil {
		log.Fatalf("failed to start server: %v", err)
	}
}

func configureRuntimeLogging() {
	if config.NormalizeLogLevel(config.AppConfig.LogLevel) == "debug" {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	if config.NormalizeLogLevel(config.AppConfig.LogLevel) == "silent" {
		gin.DefaultWriter = io.Discard
		gin.DefaultErrorWriter = io.Discard
	}
}

func registerV1(v1 *gin.RouterGroup) {
	registerPassportRoutes(v1)
	registerGuestRoutes(v1)
	registerUserRoutes(v1)
	registerClientRoutes(v1)
	registerServerRoutesV1(v1)
}

func registerV2(v2 *gin.RouterGroup) {
	registerPassportRoutes(v2)
	registerUserRoutesV2(v2)
	registerClientRoutesV2(v2)
	registerServerRoutesV2(v2)
	registerAdminRoutesV2(v2)
}

func registerPassportRoutes(group *gin.RouterGroup) {
	passport := group.Group("/passport")
	passport.POST("/auth/register", handler.Register)
	passport.POST("/auth/login", handler.Login)
	passport.GET("/auth/token2Login", handler.Token2Login)
	passport.POST("/auth/forget", handler.ForgetPassword)
	passport.POST("/auth/getQuickLoginUrl", handler.PassportGetQuickLoginURL)
	passport.POST("/auth/loginWithMailLink", handler.PassportLoginWithMailLink)
	passport.POST("/comm/sendEmailVerify", handler.SendEmailVerify)
	passport.POST("/comm/pv", handler.PassportPV)
}

func registerGuestRoutes(v1 *gin.RouterGroup) {
	guest := v1.Group("/guest")
	guest.GET("/plan/fetch", handler.GuestPlanFetch)
	guest.POST("/telegram/webhook", handler.NotImplemented("guest.telegram.webhook"))
	guest.Any("/payment/notify/:method/:uuid", handler.NotImplemented("guest.payment.notify"))
	guest.GET("/comm/config", handler.GuestConfig)
}

func registerUserRoutes(v1 *gin.RouterGroup) {
	user := v1.Group("/user")
	user.Use(middleware.Auth())
	user.GET("/resetSecurity", handler.UserResetSecurity)
	user.GET("/info", handler.UserInfo)
	user.POST("/changePassword", handler.UserChangePassword)
	user.POST("/update", handler.UserUpdate)
	user.GET("/getSubscribe", handler.UserGetSubscribe)
	user.GET("/getStat", handler.UserGetStat)
	user.GET("/checkLogin", handler.UserCheckLogin)
	user.GET("/plan/fetch", handler.GuestPlanFetch)
	user.GET("/server/fetch", handler.UserServerFetch)
	user.GET("/comm/config", handler.UserCommConfig)

	user.POST("/transfer", handler.UserTransfer)
	user.POST("/getQuickLoginUrl", handler.UserGetQuickLoginURL)
	user.GET("/notice/fetch", handler.UserNoticeFetch)
	user.POST("/coupon/check", handler.UserCouponCheck)
	user.POST("/gift-card/check", handler.UserGiftCardCheck)
	user.POST("/gift-card/redeem", handler.UserGiftCardRedeem)
	user.GET("/gift-card/history", handler.UserGiftCardHistory)
	user.GET("/gift-card/detail", handler.UserGiftCardDetail)
	user.GET("/gift-card/types", handler.UserGiftCardTypes)
	user.GET("/telegram/getBotInfo", handler.UserTelegramBotInfo)
	user.POST("/comm/getStripePublicKey", handler.UserGetStripePublicKey)
	user.GET("/stat/getTrafficLog", handler.UserTrafficLog)
	user.POST("/order/save", handler.UserOrderSave)
	user.POST("/order/checkout", handler.UserOrderCheckout)
	user.GET("/order/check", handler.UserOrderCheck)
	user.GET("/order/detail", handler.UserOrderDetail)
	user.GET("/order/fetch", handler.UserOrderFetch)
	user.GET("/order/getPaymentMethod", handler.UserOrderGetPaymentMethod)
	user.POST("/order/cancel", handler.UserOrderCancel)
	user.GET("/invite/save", handler.UserInviteSave)
	user.GET("/invite/fetch", handler.UserInviteFetch)
	user.GET("/invite/details", handler.UserInviteDetails)
	user.GET("/getActiveSession", handler.UserGetActiveSession)
	user.POST("/removeActiveSession", handler.UserRemoveActiveSession)
	user.GET("/knowledge/fetch", handler.UserKnowledgeFetch)
	user.GET("/knowledge/getCategory", handler.UserKnowledgeCategories)
	user.POST("/ticket/reply", handler.UserTicketReply)
	user.POST("/ticket/close", handler.UserTicketClose)
	user.POST("/ticket/save", handler.UserTicketSave)
	user.GET("/ticket/fetch", handler.UserTicketFetch)
	user.POST("/ticket/withdraw", handler.UserTicketWithdraw)

	// Integrated User Features
	user.GET("/real-name-verification/status", handler.PluginRealNameStatus)
	user.POST("/real-name-verification/submit", handler.PluginRealNameSubmit)
	user.GET("/user-online-devices/get-ip", handler.PluginUserOnlineDevicesGetIP)
	// User IPv6 subscription - read-only status check (enable/disable is admin-only)
	user.GET("/user-add-ipv6-subscription/check", handler.PluginUserAddIPv6Check)
}

func registerUserRoutesV2(v2 *gin.RouterGroup) {
	user := v2.Group("/user")
	user.Use(middleware.Auth())
	user.GET("/resetSecurity", handler.UserResetSecurity)
	user.GET("/info", handler.UserInfo)
}

func registerClientRoutes(v1 *gin.RouterGroup) {
	client := v1.Group("/client")
	client.Use(middleware.ClientAuth())
	client.GET("/subscribe", handler.ClientSubscribe)
	client.GET("/app/getConfig", handler.ClientAppConfigV1)
	client.GET("/app/getVersion", handler.ClientAppVersion)
}

func registerClientRoutesV2(v2 *gin.RouterGroup) {
	client := v2.Group("/client")
	client.Use(middleware.ClientAuth())
	client.GET("/app/getConfig", handler.ClientAppConfigV2)
	client.GET("/app/getVersion", handler.ClientAppVersion)
}

func registerServerRoutesV1(v1 *gin.RouterGroup) {
	server := v1.Group("/server")

	uniProxy := server.Group("/UniProxy")
	uniProxy.Use(middleware.NodeAuth())
	uniProxy.GET("/config", handler.NodeConfig)
	uniProxy.GET("/user", handler.NodeUser)
	uniProxy.POST("/push", handler.NodePush)
	uniProxy.GET("/alive", handler.NodeAlive)
	uniProxy.POST("/alive", handler.NodeAlive)
	uniProxy.GET("/alivelist", handler.NodeAliveList)
	uniProxy.POST("/status", handler.NodeStatus)

	shadowsocks := server.Group("/ShadowsocksTidalab")
	shadowsocks.Use(middleware.NodeAuth())
	shadowsocks.GET("/user", handler.NodeShadowsocksTidalabUser)
	shadowsocks.POST("/submit", handler.NodeTidalabSubmit)

	trojan := server.Group("/TrojanTidalab")
	trojan.Use(middleware.NodeAuth())
	trojan.GET("/config", handler.NodeTrojanTidalabConfig)
	trojan.GET("/user", handler.NodeTrojanTidalabUser)
	trojan.POST("/submit", handler.NodeTidalabSubmit)
}

func registerServerRoutesV2(v2 *gin.RouterGroup) {
	server := v2.Group("/server")
	server.Use(middleware.NodeAuth())
	server.POST("/handshake", handler.NodeHandshake)
	server.POST("/report", handler.NodeReport)
	server.GET("/config", handler.NodeConfig)
	server.GET("/user", handler.NodeUser)
	server.POST("/push", handler.NodePush)
	server.GET("/alive", handler.NodeAlive)
	server.POST("/alive", handler.NodeAlive)
	server.GET("/alivelist", handler.NodeAliveList)
	server.POST("/status", handler.NodeStatus)
}

func registerAdminRoutesV2(v2 *gin.RouterGroup) {
	admin := v2.Group("/" + service.GetAdminSecurePath())
	admin.Use(middleware.Auth(), middleware.AdminAuth())

	admin.GET("/config/fetch", handler.AdminConfigFetch)
	admin.POST("/config/save", handler.AdminConfigSave)
	admin.GET("/config/getEmailTemplate", handler.AdminGetEmailTemplate)
	admin.POST("/config/testSendMail", handler.AdminTestSendMail)
	admin.POST("/config/setTelegramWebhook", handler.AdminSetTelegramWebhook)
	admin.GET("/dashboard/summary", handler.AdminDashboardSummary)

	admin.GET("/stat/getStats", handler.AdminDashboardSummary)
	admin.GET("/stat/getOverride", handler.AdminDashboardSummary)
	admin.GET("/stat/getTrafficRank", handler.AdminGetTrafficRank)
	admin.GET("/stat/getOrder", handler.AdminGetOrderStats)
	admin.POST("/stat/getStatUser", handler.AdminGetStatUser)

	admin.GET("/system/getSystemStatus", handler.AdminSystemStatus)
	admin.GET("/system/getQueueStats", handler.AdminSystemQueueStats)
	admin.GET("/system/getQueueWorkload", handler.AdminSystemQueueStats)
	admin.GET("/system/getQueueMasters", handler.AdminSystemQueueStats)
	admin.GET("/system/getHorizonFailedJobs", handler.AdminSystemQueueStats)

	admin.GET("/server/group/fetch", handler.AdminServerGroupsFetch)
	admin.POST("/server/group/save", handler.AdminServerGroupSave)
	admin.POST("/server/group/drop", handler.AdminServerGroupDrop)
	admin.GET("/server/route/fetch", handler.AdminServerRoutesFetch)
	admin.POST("/server/route/save", handler.AdminServerRouteSave)
	admin.POST("/server/route/drop", handler.AdminServerRouteDrop)
	admin.GET("/server/manage/getNodes", handler.AdminServerManageGetNodes)
	admin.POST("/server/manage/sort", handler.AdminServerManageSort)
	admin.POST("/server/manage/update", handler.AdminServerManageUpdate)
	admin.POST("/server/manage/save", handler.AdminServerManageSave)
	admin.POST("/server/manage/drop", handler.AdminServerManageDrop)
	admin.POST("/server/manage/copy", handler.AdminServerManageCopy)
	admin.POST("/server/manage/batchDelete", handler.AdminServerManageBatchDelete)
	admin.POST("/server/manage/resetTraffic", handler.AdminServerManageResetTraffic)
	admin.POST("/server/manage/batchResetTraffic", handler.AdminServerManageBatchResetTraffic)
	admin.GET("/plan/fetch", handler.AdminPlansFetch)
	admin.POST("/plan/save", handler.AdminPlanSave)
	admin.POST("/plan/drop", handler.AdminPlanDrop)
	admin.POST("/plan/sort", handler.AdminPlanSort)

	admin.GET("/order/fetch", handler.AdminOrdersFetch)
	admin.POST("/order/fetch", handler.AdminOrdersFetch)
	admin.POST("/order/detail", handler.AdminOrderDetail)
	admin.POST("/order/paid", handler.AdminOrderPaid)
	admin.POST("/order/cancel", handler.AdminOrderCancel)
	admin.POST("/order/update", handler.AdminOrderUpdate)
	admin.POST("/order/assign", handler.AdminOrderAssign)

	admin.GET("/user/fetch", handler.AdminUsersFetch)
	admin.POST("/user/fetch", handler.AdminUsersFetch)
	admin.POST("/user/update", handler.AdminUserUpdate)
	admin.POST("/user/ban", handler.AdminUserBan)
	admin.POST("/user/resetSecret", handler.AdminUserResetSecret)
	admin.POST("/user/sendMail", handler.AdminUserSendMail)
	admin.POST("/user/destroy", handler.AdminUserDelete)
	admin.POST("/user/resetTraffic", handler.AdminUserResetTraffic)
	admin.POST("/user/drop", handler.AdminUserDelete)
	admin.GET("/ticket/fetch", handler.AdminTicketsFetch)
	admin.POST("/ticket/fetch", handler.AdminTicketsFetch)
	admin.GET("/traffic-reset/fetch", handler.AdminTrafficResetFetch)
	admin.GET("/traffic-reset/logs", handler.AdminTrafficResetFetch)
	admin.POST("/traffic-reset/reset-user", handler.AdminTrafficResetUser)
	admin.GET("/traffic-reset/user/:id/history", handler.AdminTrafficResetUserHistory)

	admin.GET("/notice/fetch", handler.AdminNoticeFetch)
	admin.POST("/notice/save", handler.AdminNoticeSave)
	admin.POST("/notice/drop", handler.AdminNoticeDrop)
	admin.POST("/notice/show", handler.AdminNoticeShow)
	admin.POST("/notice/sort", handler.AdminNoticeSort)

	admin.GET("/knowledge/fetch", handler.AdminKnowledgeFetch)
	admin.POST("/knowledge/save", handler.AdminKnowledgeSave)
	admin.POST("/knowledge/drop", handler.AdminKnowledgeDrop)
	admin.POST("/knowledge/sort", handler.AdminKnowledgeSort)

	// Integrated Admin Features
	admin.GET("/realname/records", handler.PluginRealNameRecords)
	admin.POST("/realname/clear-cache", handler.PluginRealNameClearCache)
	admin.POST("/realname/review/:userId", handler.PluginRealNameReview)
	admin.POST("/realname/reset/:userId", handler.PluginRealNameReset)
	admin.POST("/realname/sync-all", handler.PluginRealNameSyncAll)
	admin.POST("/realname/approve-all", handler.PluginRealNameApproveAll)
	admin.GET("/user-online-devices/users", handler.PluginUserOnlineDevicesUsers)
	admin.GET("/user-add-ipv6-subscription/users", handler.AdminIPv6SubscriptionUsers)
	admin.GET("/user-add-ipv6-subscription/config", handler.AdminIPv6SubscriptionConfigFetch)
	admin.POST("/user-add-ipv6-subscription/config", handler.AdminIPv6SubscriptionConfigSave)
	admin.POST("/user-add-ipv6-subscription/enable/:userId", handler.AdminIPv6SubscriptionEnable)
	admin.POST("/user-add-ipv6-subscription/disable/:userId", handler.AdminIPv6SubscriptionDisable)
	admin.POST("/user-add-ipv6-subscription/sync-password/:userId", handler.AdminIPv6SubscriptionSyncPassword)
}

func registerWebRoutes(router *gin.Engine) {
	themeRoot := filepath.Join(".", "frontend", "theme")
	adminRoot := filepath.Join(".", "frontend", "admin")

	if _, err := os.Stat(themeRoot); err == nil {
		router.Static("/theme", themeRoot)
	}
	if _, err := os.Stat(adminRoot); err == nil {
		router.Static("/admin-assets", adminRoot)
	}

	securePath := "/" + service.GetAdminSecurePath()
	subscribePath := "/" + service.GetSubscribePath()
	router.GET("/", handler.UserThemePage)
	router.GET("/dashboard", handler.UserThemePage)
	router.GET(subscribePath+"/:token", handler.Subscribe)
	router.GET(securePath, handler.AdminAppPage)
	router.GET(securePath+"/", handler.AdminAppPage)
	router.GET(securePath+"/plugin-panel/:kind", handler.AdminPluginPanelPage)
	router.GET(securePath+"/plugins/:plugin", handler.AdminAppPage)
	router.NoRoute(func(c *gin.Context) {
		path := c.Request.URL.Path
		if path == securePath || strings.HasPrefix(path, securePath+"/") {
			handler.AdminAppPage(c)
			return
		}
		c.JSON(404, gin.H{"message": "not found"})
	})
}
