package handler

import (
	"strconv"
	"strings"
	"time"
	"xboard-go/internal/database"
	"xboard-go/internal/model"
	"xboard-go/internal/service"

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

func PluginUserOnlineDevicesUsers(c *gin.Context) {
	if !service.IsPluginEnabled(service.PluginUserOnlineDevices) {
		Fail(c, 400, "plugin is not enabled")
		return
	}

	page := parsePositiveInt(c.DefaultQuery("page", "1"), 1)
	perPage := parsePositiveInt(c.DefaultQuery("per_page", "20"), 20)
	keyword := strings.TrimSpace(c.Query("keyword"))

	query := database.DB.Model(&model.User{}).Order("id DESC")
	if keyword != "" {
		query = query.Where("email LIKE ? OR id = ?", "%"+keyword+"%", keyword)
	}

	var total int64
	query.Count(&total)

	var users []model.User
	if err := query.Offset((page - 1) * perPage).Limit(perPage).Find(&users).Error; err != nil {
		Fail(c, 500, "failed to fetch users")
		return
	}

	userIDs := make([]int, 0, len(users))
	for _, user := range users {
		userIDs = append(userIDs, user.ID)
	}
	devices := service.GetUsersDevices(userIDs)

	list := make([]gin.H, 0, len(users))
	usersWithOnlineIP := 0
	totalOnlineIPs := 0
	for _, user := range users {
		subscriptionName := "No subscription"
		if user.PlanID != nil {
			var plan model.Plan
			if database.DB.First(&plan, *user.PlanID).Error == nil {
				subscriptionName = plan.Name
			}
		}

		ips := devices[user.ID]
		if len(ips) > 0 {
			usersWithOnlineIP++
			totalOnlineIPs += len(ips)
		}

		list = append(list, gin.H{
			"id":                user.ID,
			"email":             user.Email,
			"subscription_name": subscriptionName,
			"online_count":      len(ips),
			"online_devices":    ips,
			"last_online_text":  formatTimeValue(user.LastOnlineAt),
			"created_text":      formatUnixValue(user.CreatedAt),
		})
	}

	Success(c, gin.H{
		"list": list,
		"filters": gin.H{
			"keyword":  keyword,
			"per_page": perPage,
		},
		"summary": gin.H{
			"page_users":           len(users),
			"users_with_online_ip": usersWithOnlineIP,
			"total_online_ips":     totalOnlineIPs,
			"current_page":         page,
		},
		"pagination": gin.H{
			"current":   page,
			"last_page": calculateLastPage(total, perPage),
			"per_page":  perPage,
			"total":     total,
		},
	})
}

func PluginUserOnlineDevicesGetIP(c *gin.Context) {
	if !service.IsPluginEnabled(service.PluginUserOnlineDevices) {
		Fail(c, 400, "plugin is not enabled")
		return
	}

	user, ok := currentUser(c)
	if !ok {
		Fail(c, 401, "unauthorized")
		return
	}

	devices := service.GetUsersDevices([]int{user.ID})
	ips := devices[user.ID]
	authToken, _ := c.Get("auth_token")
	currentToken, _ := authToken.(string)
	sessions := service.GetUserSessions(user.ID, currentToken)
	currentID := currentSessionID(c)

	sessionItems := make([]gin.H, 0, len(sessions))
	for _, session := range sessions {
		sessionItems = append(sessionItems, gin.H{
			"id":           session.ID,
			"name":         session.Name,
			"user_agent":   session.UserAgent,
			"ip":           firstString(session.IP, "-"),
			"created_at":   session.CreatedAt,
			"last_used_at": session.LastUsedAt,
			"expires_at":   session.ExpiresAt,
			"is_current":   session.ID == currentID,
		})
	}
	Success(c, gin.H{
		"ips": ips,
		"session_overview": gin.H{
			"online_ip_count":      len(ips),
			"online_ips":           ips,
			"online_device_count":  len(ips),
			"device_limit":         user.DeviceLimit,
			"last_online_at":       user.LastOnlineAt,
			"active_session_count": len(sessionItems),
			"sessions":             sessionItems,
		},
	})
}

func PluginUserAddIPv6Check(c *gin.Context) {
	if !service.IsPluginEnabled(service.PluginUserAddIPv6) {
		Fail(c, 400, "plugin is not enabled")
		return
	}

	user, ok := currentUser(c)
	if !ok {
		Fail(c, 401, "unauthorized")
		return
	}

	if user.PlanID == nil {
		Success(c, gin.H{"allowed": false, "reason": "No active plan"})
		return
	}

	var plan model.Plan
	if err := database.DB.First(&plan, *user.PlanID).Error; err != nil {
		Success(c, gin.H{"allowed": false, "reason": "No active plan"})
		return
	}

	ipv6Email := service.IPv6ShadowEmail(user.Email)
	var count int64
	database.DB.Model(&model.User{}).Where("email = ?", ipv6Email).Count(&count)

	Success(c, gin.H{
		"allowed":   service.PluginPlanAllowed(&plan),
		"is_active": count > 0,
	})
}

func PluginUserAddIPv6Enable(c *gin.Context) {
	if !service.IsPluginEnabled(service.PluginUserAddIPv6) {
		Fail(c, 400, "plugin is not enabled")
		return
	}

	user, ok := currentUser(c)
	if !ok {
		Fail(c, 401, "unauthorized")
		return
	}

	if !service.SyncIPv6ShadowAccount(user) {
		Fail(c, 403, "your plan does not support IPv6 subscription")
		return
	}

	SuccessMessage(c, "IPv6 subscription enabled/synced", true)
}

func PluginUserAddIPv6SyncPassword(c *gin.Context) {
	if !service.IsPluginEnabled(service.PluginUserAddIPv6) {
		Fail(c, 400, "plugin is not enabled")
		return
	}

	user, ok := currentUser(c)
	if !ok {
		Fail(c, 401, "unauthorized")
		return
	}

	ipv6Email := service.IPv6ShadowEmail(user.Email)
	result := database.DB.Model(&model.User{}).Where("email = ?", ipv6Email).Update("password", user.Password)
	if result.Error != nil {
		Fail(c, 404, "IPv6 user not found")
		return
	}
	if result.RowsAffected == 0 {
		Fail(c, 404, "IPv6 user not found")
		return
	}

	SuccessMessage(c, "Password synced to IPv6 account", true)
}

func AdminConfigFetch(c *gin.Context) {
	Success(c, gin.H{
		"app_name":             service.MustGetString("app_name", "XBoard"),
		"app_url":              service.GetAppURL(),
		"secure_path":          service.GetAdminSecurePath(),
		"server_pull_interval": service.MustGetInt("server_pull_interval", 60),
		"server_push_interval": service.MustGetInt("server_push_interval", 60),
	})
}

func AdminSystemStatus(c *gin.Context) {
	Success(c, gin.H{
		"server_time": time.Now().Unix(),
		"app_name":    service.MustGetString("app_name", "XBoard"),
		"app_url":     service.GetAppURL(),
	})
}

func AdminPluginsList(c *gin.Context) {
	var plugins []model.Plugin
	if err := database.DB.Order("id ASC").Find(&plugins).Error; err != nil {
		Fail(c, 500, "failed to fetch plugins")
		return
	}
	Success(c, plugins)
}

func AdminPluginTypes(c *gin.Context) {
	Success(c, []string{"feature", "payment"})
}

func AdminPluginIntegrationStatus(c *gin.Context) {
	Success(c, gin.H{
		"user_online_devices": gin.H{
			"enabled":   service.IsPluginEnabled(service.PluginUserOnlineDevices),
			"status":    "complete",
			"summary":   "用户侧在线设备概览与后台设备监控已接入 Go 后端。",
			"endpoints": []string{"/api/v1/user/user-online-devices/get-ip", "/api/v1/" + service.GetAdminSecurePath() + "/user-online-devices/users"},
		},
		"real_name_verification": gin.H{
			"enabled":   service.IsPluginEnabled(service.PluginRealNameVerification),
			"status":    "complete",
			"summary":   "实名状态查询、提交、后台审核与批量同步均已整合，并补齐 auto_approve/allow_resubmit_after_reject 行为。",
			"endpoints": []string{"/api/v1/user/real-name-verification/status", "/api/v1/user/real-name-verification/submit", "/api/v1/" + service.GetAdminSecurePath() + "/realname/records"},
		},
		"user_add_ipv6_subscription": gin.H{
			"enabled":   service.IsPluginEnabled(service.PluginUserAddIPv6),
			"status":    "integrated_with_runtime_sync",
			"summary":   "用户启用、密码同步与运行时影子账号同步已接入；订单生命周期自动钩子仍依赖后续完整订单流重构。",
			"endpoints": []string{"/api/v1/user/user-add-ipv6-subscription/check", "/api/v1/user/user-add-ipv6-subscription/enable", "/api/v1/user/user-add-ipv6-subscription/sync-password"},
		},
	})
}

func parsePositiveInt(raw string, defaultValue int) int {
	value, err := strconv.Atoi(strings.TrimSpace(raw))
	if err != nil || value <= 0 {
		return defaultValue
	}
	return value
}

func calculateLastPage(total int64, perPage int) int {
	if perPage <= 0 {
		return 1
	}
	last := int((total + int64(perPage) - 1) / int64(perPage))
	if last == 0 {
		return 1
	}
	return last
}

func formatUnixValue(value int64) string {
	if value <= 0 {
		return "-"
	}
	return time.Unix(value, 0).Format("2006-01-02 15:04:05")
}

func formatTimeValue(value *time.Time) string {
	if value == nil {
		return "-"
	}
	return value.Format("2006-01-02 15:04:05")
}
