package admin

import (
	"fmt"
	"log"
	"time"
	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/model"
	"verification-platform-backend/internal/service"
	"verification-platform-backend/pkg/response"

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

type DeviceWithDetails struct {
	model.UserDevice
	OnlineSessions int `json:"online_sessions"`
}

func SetupDeviceRoutes(r *gin.RouterGroup) {
	devices := r.Group("/devices")
	{
		devices.GET("", handleGetDevices)
		devices.PUT("/:id/status", handleUpdateDeviceStatus)
		devices.DELETE("/:id", handleUnbindDevice)
		devices.DELETE("/batch", handleBatchUnbindDevices)
		devices.POST("/batch/status", handleBatchUpdateDeviceStatus)
		devices.POST("/:id/force-offline", handleForceOfflineDevice)
	}

	sessions := r.Group("/sessions")
	{
		sessions.GET("", handleGetSessions)
		sessions.DELETE("/:id", handleDeleteSession)
	}
}

func handleGetDevices(c *gin.Context) {
	userID := c.GetUint("user_id")
	log.Printf("[DEBUG] handleGetDevices called, userID: %d", userID)

	userIDFilter := c.Query("user_id")
	deviceIDFilter := c.Query("device_id")

	var devices []model.UserDevice
	var appHeartbeatTimeoutMap map[uint]int

	var ownApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&ownApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	var agentApps []model.AgentApplication
	if err := database.DB.Where("agent_id = ? AND is_received = ?", userID, true).Find(&agentApps).Error; err != nil {
		log.Printf("[DEBUG] Failed to get agent apps: %v", err)
	}

	appHeartbeatTimeoutMap = make(map[uint]int)
	var appIDs []uint

	for _, app := range ownApps {
		timeout := app.HeartbeatTimeout
		if timeout == 0 {
			timeout = 300
		}
		appHeartbeatTimeoutMap[app.ID] = timeout
		appIDs = append(appIDs, app.ID)
	}

	for _, agentApp := range agentApps {
		var app model.Application
		if err := database.DB.First(&app, agentApp.ApplicationID).Error; err != nil {
			continue
		}
		timeout := app.HeartbeatTimeout
		if timeout == 0 {
			timeout = 300
		}
		appHeartbeatTimeoutMap[app.ID] = timeout
		appIDs = append(appIDs, app.ID)
	}

	if len(appIDs) == 0 {
		response.Success(c, gin.H{"devices": []DeviceWithDetails{}})
		return
	}

	query := database.DB.Preload("User").Preload("Application").Where("application_id IN ?", appIDs)

	if userIDFilter != "" {
		query = query.Where("user_id = ?", userIDFilter)
	}

	if deviceIDFilter != "" {
		query = query.Where("device_id = ?", deviceIDFilter)
	}

	if err := query.Find(&devices).Error; err != nil {
		response.Error(c, 500, "获取设备列表失败")
		return
	}

	devicesWithDetails := make([]DeviceWithDetails, 0, len(devices))
	for _, device := range devices {
		heartbeatTimeout := appHeartbeatTimeoutMap[device.ApplicationID]
		timeoutThreshold := time.Now().Add(-time.Duration(heartbeatTimeout) * time.Second)

		var onlineSessionCount int64
		database.DB.Model(&model.DeviceSession{}).
			Where("device_id = ? AND last_heartbeat > ?", device.ID, timeoutThreshold).
			Count(&onlineSessionCount)

		devicesWithDetails = append(devicesWithDetails, DeviceWithDetails{
			UserDevice:     device,
			OnlineSessions: int(onlineSessionCount),
		})
	}

	response.Success(c, gin.H{"devices": devicesWithDetails})
}

func handleUpdateDeviceStatus(c *gin.Context) {
	userID := c.GetUint("user_id")
	deviceID := c.Param("id")

	var req struct {
		Status string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	var device model.UserDevice
	if err := database.DB.First(&device, deviceID).Error; err != nil {
		response.Error(c, 404, "设备不存在")
		return
	}

	var app model.Application
	if err := database.DB.First(&app, device.ApplicationID).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}

	if app.UserID != userID {
		var agentApp model.AgentApplication
		if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
			response.Error(c, 403, "无权限修改该设备")
			return
		}
	}

	device.Status = req.Status
	if err := database.DB.Save(&device).Error; err != nil {
		response.Error(c, 500, "更新设备状态失败")
		return
	}

	response.Success(c, device)
}

func handleUnbindDevice(c *gin.Context) {
	userID := c.GetUint("user_id")
	deviceID := c.Param("id")

	var device model.UserDevice
	if err := database.DB.First(&device, deviceID).Error; err != nil {
		response.Error(c, 404, "设备不存在")
		return
	}

	var app model.Application
	if err := database.DB.First(&app, device.ApplicationID).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}

	if app.UserID != userID {
		var agentApp model.AgentApplication
		if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
			response.Error(c, 403, "无权限解绑该设备")
			return
		}
	}

	database.DB.Where("device_id = ?", device.ID).Delete(&model.DeviceSession{})

	if err := database.DB.Delete(&device).Error; err != nil {
		response.Error(c, 500, "解绑设备失败")
		return
	}

	service.LogOperation(c, "unbind", "device", &device.ID, fmt.Sprintf("解绑设备: %s (应用: %s)", device.DeviceID, app.Name), nil)

	response.Success(c, nil)
}

func handleBatchUnbindDevices(c *gin.Context) {
	userID := c.GetUint("user_id")
	var req struct {
		DeviceIDs []uint `json:"device_ids"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	var devices []model.UserDevice
	if err := database.DB.Where("id IN ?", req.DeviceIDs).Find(&devices).Error; err != nil {
		response.Error(c, 500, "获取设备列表失败")
		return
	}

	var validDeviceIDs []uint
	for _, device := range devices {
		var app model.Application
		if err := database.DB.First(&app, device.ApplicationID).Error; err != nil {
			continue
		}

		if app.UserID == userID {
			validDeviceIDs = append(validDeviceIDs, device.ID)
		} else {
			var agentApp model.AgentApplication
			if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err == nil {
				validDeviceIDs = append(validDeviceIDs, device.ID)
			}
		}
	}

	if len(validDeviceIDs) > 0 {
		database.DB.Where("device_id IN ?", validDeviceIDs).Delete(&model.DeviceSession{})
		if err := database.DB.Where("id IN ?", validDeviceIDs).Delete(&model.UserDevice{}).Error; err != nil {
			response.Error(c, 500, "批量解绑失败")
			return
		}
	}

	service.LogOperation(c, "batch_unbind", "device", nil, fmt.Sprintf("批量解绑设备: %d个", len(validDeviceIDs)), nil)

	response.Success(c, nil)
}

func handleBatchUpdateDeviceStatus(c *gin.Context) {
	userID := c.GetUint("user_id")
	var req struct {
		DeviceIDs []uint `json:"device_ids"`
		Status    string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	var devices []model.UserDevice
	if err := database.DB.Where("id IN ?", req.DeviceIDs).Find(&devices).Error; err != nil {
		response.Error(c, 500, "获取设备列表失败")
		return
	}

	var validDeviceIDs []uint
	for _, device := range devices {
		var app model.Application
		if err := database.DB.First(&app, device.ApplicationID).Error; err != nil {
			continue
		}

		if app.UserID == userID {
			validDeviceIDs = append(validDeviceIDs, device.ID)
		} else {
			var agentApp model.AgentApplication
			if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err == nil {
				validDeviceIDs = append(validDeviceIDs, device.ID)
			}
		}
	}

	if len(validDeviceIDs) > 0 {
		if err := database.DB.Model(&model.UserDevice{}).Where("id IN ?", validDeviceIDs).Update("status", req.Status).Error; err != nil {
			response.Error(c, 500, "批量更新状态失败")
			return
		}
	}

	response.Success(c, nil)
}

type SessionWithDetails struct {
	model.DeviceSession
	DeviceID   string `json:"device_identifier"`
	DeviceName string `json:"device_name"`
	Username   string `json:"username"`
	AppName    string `json:"app_name"`
	IsOnline   bool   `json:"is_online"`
}

func handleGetSessions(c *gin.Context) {
	userID := c.GetUint("user_id")
	deviceIDFilter := c.Query("device_id")
	appIDFilter := c.Query("app_id")

	var ownApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&ownApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	var agentApps []model.AgentApplication
	if err := database.DB.Where("agent_id = ? AND is_received = ?", userID, true).Find(&agentApps).Error; err != nil {
		log.Printf("[DEBUG] Failed to get agent apps: %v", err)
	}

	appHeartbeatTimeoutMap := make(map[uint]int)
	var appIDs []uint

	for _, app := range ownApps {
		timeout := app.HeartbeatTimeout
		if timeout == 0 {
			timeout = 300
		}
		appHeartbeatTimeoutMap[app.ID] = timeout
		appIDs = append(appIDs, app.ID)
	}

	for _, agentApp := range agentApps {
		var app model.Application
		if err := database.DB.First(&app, agentApp.ApplicationID).Error; err != nil {
			continue
		}
		timeout := app.HeartbeatTimeout
		if timeout == 0 {
			timeout = 300
		}
		appHeartbeatTimeoutMap[app.ID] = timeout
		appIDs = append(appIDs, app.ID)
	}

	if len(appIDs) == 0 {
		response.Success(c, gin.H{"sessions": []SessionWithDetails{}})
		return
	}

	query := database.DB.Model(&model.DeviceSession{}).Where("application_id IN ?", appIDs)

	if deviceIDFilter != "" {
		query = query.Where("device_id = ?", deviceIDFilter)
	}

	if appIDFilter != "" {
		query = query.Where("application_id = ?", appIDFilter)
	}

	var sessions []model.DeviceSession
	if err := query.Find(&sessions).Error; err != nil {
		response.Error(c, 500, "获取会话列表失败")
		return
	}

	sessionsWithDetails := make([]SessionWithDetails, 0, len(sessions))
	for _, session := range sessions {
		var device model.UserDevice
		if err := database.DB.First(&device, session.DeviceID).Error; err != nil {
			continue
		}

		var user model.AppUser
		if err := database.DB.First(&user, session.UserID).Error; err != nil {
			continue
		}

		var app model.Application
		if err := database.DB.First(&app, session.ApplicationID).Error; err != nil {
			continue
		}

		heartbeatTimeout := appHeartbeatTimeoutMap[session.ApplicationID]
		timeoutThreshold := time.Now().Add(-time.Duration(heartbeatTimeout) * time.Second)
		isOnline := session.LastHeartbeat != nil && session.LastHeartbeat.After(timeoutThreshold)

		sessionsWithDetails = append(sessionsWithDetails, SessionWithDetails{
			DeviceSession: session,
			DeviceID:      device.DeviceID,
			DeviceName:    device.DeviceName,
			Username:      user.Username,
			AppName:       app.Name,
			IsOnline:      isOnline,
		})
	}

	response.Success(c, gin.H{"sessions": sessionsWithDetails})
}

func handleDeleteSession(c *gin.Context) {
	userID := c.GetUint("user_id")
	sessionID := c.Param("id")

	if sessionID == "" {
		response.Error(c, 400, "会话ID不能为空")
		return
	}

	var session model.DeviceSession
	if err := database.DB.First(&session, sessionID).Error; err != nil {
		response.Error(c, 404, "会话不存在")
		return
	}

	var ownApps []model.Application
	database.DB.Where("user_id = ?", userID).Find(&ownApps)
	ownAppIDs := make([]uint, len(ownApps))
	for i, app := range ownApps {
		ownAppIDs[i] = app.ID
	}

	var agentApps []model.AgentApplication
	database.DB.Where("agent_id = ? AND is_received = ?", userID, true).Find(&agentApps)
	agentAppIDs := make([]uint, 0)
	for _, agentApp := range agentApps {
		agentAppIDs = append(agentAppIDs, agentApp.ApplicationID)
	}

	validAppIDs := append(ownAppIDs, agentAppIDs...)
	isValid := false
	for _, appID := range validAppIDs {
		if session.ApplicationID == appID {
			isValid = true
			break
		}
	}

	if !isValid {
		response.Error(c, 403, "无权操作此会话")
		return
	}

	if err := database.DB.Delete(&session).Error; err != nil {
		response.Error(c, 500, "删除会话失败")
		return
	}

	response.Success(c, nil)
}

func handleForceOfflineDevice(c *gin.Context) {
	userID := c.GetUint("user_id")
	deviceID := c.Param("id")

	if deviceID == "" {
		response.Error(c, 400, "设备ID不能为空")
		return
	}

	var device model.UserDevice
	if err := database.DB.First(&device, deviceID).Error; err != nil {
		response.Error(c, 404, "设备不存在")
		return
	}

	var ownApps []model.Application
	database.DB.Where("user_id = ?", userID).Find(&ownApps)
	ownAppIDs := make([]uint, len(ownApps))
	for i, app := range ownApps {
		ownAppIDs[i] = app.ID
	}

	var agentApps []model.AgentApplication
	database.DB.Where("agent_id = ? AND is_received = ?", userID, true).Find(&agentApps)
	agentAppIDs := make([]uint, 0)
	for _, agentApp := range agentApps {
		agentAppIDs = append(agentAppIDs, agentApp.ApplicationID)
	}

	validAppIDs := append(ownAppIDs, agentAppIDs...)
	isValid := false
	for _, appID := range validAppIDs {
		if device.ApplicationID == appID {
			isValid = true
			break
		}
	}

	if !isValid {
		response.Error(c, 403, "无权操作此设备")
		return
	}

	var sessions []model.DeviceSession
	if err := database.DB.Where("device_id = ?", device.ID).Find(&sessions).Error; err != nil {
		response.Error(c, 500, "获取会话列表失败")
		return
	}

	if len(sessions) == 0 {
		response.Success(c, gin.H{"count": 0})
		return
	}

	if err := database.DB.Where("device_id = ?", device.ID).Delete(&model.DeviceSession{}).Error; err != nil {
		response.Error(c, 500, "强制离线失败")
		return
	}

	response.Success(c, gin.H{"count": len(sessions)})
}
