package handler

import (
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/service"
)

// DeviceHandler handles device management requests
type DeviceHandler struct {
	deviceService *service.DeviceService
}

// NewDeviceHandler creates a new DeviceHandler
func NewDeviceHandler(deviceService *service.DeviceService) *DeviceHandler {
	return &DeviceHandler{deviceService: deviceService}
}

// CreateDevice 创建设备
// @Summary 创建设备记录
// @Description 当前用户创建设备记录
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateDeviceRequest true "设备信息"
// @Success 201 {object} Response{data=domain.Device} "设备创建成功"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices [post]
func (h *DeviceHandler) CreateDevice(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	var req service.CreateDeviceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	device, err := h.deviceService.CreateDevice(c.Request.Context(), userID, &req)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"code":    0,
		"message": "success",
		"data":    device,
	})
}

// GetMyDevices 获取我的设备列表
// @Summary 获取当前用户的设备列表
// @Description 获取当前用户的所有设备记录
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices [get]
func (h *DeviceHandler) GetMyDevices(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))

	devices, total, err := h.deviceService.GetUserDevices(c.Request.Context(), userID, page, pageSize)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data": gin.H{
			"items":     devices,
			"total":    total,
			"page":     page,
			"page_size": pageSize,
		},
	})
}

// GetDevice 获取设备详情
// @Summary 获取设备详情
// @Description 根据ID获取设备详细信息
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response{data=domain.Device} "设备信息"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [get]
func (h *DeviceHandler) GetDevice(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	device, err := h.deviceService.GetDevice(c.Request.Context(), id)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data":    device,
	})
}

// UpdateDevice 更新设备
// @Summary 更新设备信息
// @Description 更新设备的基本信息
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body service.UpdateDeviceRequest true "更新信息"
// @Success 200 {object} Response{data=domain.Device} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [put]
func (h *DeviceHandler) UpdateDevice(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	var req service.UpdateDeviceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	device, err := h.deviceService.UpdateDevice(c.Request.Context(), id, &req)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data":    device,
	})
}

// DeleteDevice 删除设备
// @Summary 删除设备
// @Description 删除设备记录
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response "删除成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [delete]
func (h *DeviceHandler) DeleteDevice(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	if err := h.deviceService.DeleteDevice(c.Request.Context(), id); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "device deleted",
	})
}

// UpdateDeviceStatus 更新设备状态
// @Summary 更新设备状态
// @Description 更新设备状态（active/inactive）
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body UpdateDeviceStatusRequest true "状态信息"
// @Success 200 {object} Response "状态更新成功"
// @Failure 400 {object} Response "无效的状态值"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/status [put]
func (h *DeviceHandler) UpdateDeviceStatus(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	var req struct {
		Status string `json:"status" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	var status domain.DeviceStatus
	switch req.Status {
	case "active", "1":
		status = domain.DeviceStatusActive
	case "inactive", "0":
		status = domain.DeviceStatusInactive
	default:
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid status"})
		return
	}

	if err := h.deviceService.UpdateDeviceStatus(c.Request.Context(), id, status); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "status updated",
	})
}

// GetUserDevices 获取指定用户的设备列表
// @Summary 获取用户设备列表
// @Description 获取指定用户的设备列表（仅本人或管理员）
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/{id}/devices [get]
func (h *DeviceHandler) GetUserDevices(c *gin.Context) {
	// IDOR 修复：检查当前用户是否有权限查看指定用户的设备
	currentUserID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	// 检查是否为管理员
	roleCodes, _ := c.Get("role_codes")
	isAdmin := false
	if roles, ok := roleCodes.([]string); ok {
		for _, role := range roles {
			if role == "admin" {
				isAdmin = true
				break
			}
		}
	}

	userIDParam := c.Param("id")
	userID, err := strconv.ParseInt(userIDParam, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid user id"})
		return
	}

	// 非管理员只能查看自己的设备
	if !isAdmin && userID != currentUserID {
		c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "无权访问该用户的设备列表"})
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))

	devices, total, err := h.deviceService.GetUserDevices(c.Request.Context(), userID, page, pageSize)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data": gin.H{
			"items":     devices,
			"total":    total,
			"page":     page,
			"page_size": pageSize,
		},
	})
}

// GetAllDevices 获取所有设备列表
// @Summary 获取所有设备列表
// @Description 获取所有设备列表（仅管理员），支持游标分页和偏移分页
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param cursor query string false "游标分页游标"
// @Param size query int false "每页数量（游标模式）"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/admin/devices [get]
func (h *DeviceHandler) GetAllDevices(c *gin.Context) {
	var req service.GetAllDevicesRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	// Use cursor-based pagination when cursor is provided
	if req.Cursor != "" || req.Size > 0 {
		result, err := h.deviceService.GetAllDevicesCursor(c.Request.Context(), &req)
		if err != nil {
			handleError(c, err)
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "success",
			"data":    result,
		})
		return
	}

	// Fallback to legacy offset-based pagination
	devices, total, err := h.deviceService.GetAllDevices(c.Request.Context(), &req)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data": gin.H{
			"items":     devices,
			"total":    total,
			"page":     req.Page,
			"page_size": req.PageSize,
		},
	})
}

// TrustDeviceRequest 信任设备请求
type TrustDeviceRequest struct {
	TrustDuration string `json:"trust_duration"` // 信任持续时间，如 "30d" 表示30天
}

// TrustDevice 设置设备为信任设备
// @Summary 设置设备为信任设备
// @Description 将指定设备设置为信任设备，在信任期内免二次验证
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body TrustDeviceRequest true "信任配置"
// @Success 200 {object} Response "设置成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/trust [post]
func (h *DeviceHandler) TrustDevice(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	var req TrustDeviceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	// 解析信任持续时间
	trustDuration := parseDuration(req.TrustDuration)

	if err := h.deviceService.TrustDevice(c.Request.Context(), id, trustDuration); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "device trusted",
	})
}

// TrustDeviceByDeviceID 根据设备标识设置设备为信任状态
// @Summary 根据设备标识设置信任
// @Description 根据设备唯一标识字符串设置设备为信任状态
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param deviceId path string true "设备唯一标识"
// @Param request body TrustDeviceRequest true "信任配置"
// @Success 200 {object} Response "设置成功"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/trust/{deviceId} [post]
func (h *DeviceHandler) TrustDeviceByDeviceID(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	deviceID := c.Param("deviceId")
	if deviceID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	var req TrustDeviceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	// 解析信任持续时间
	trustDuration := parseDuration(req.TrustDuration)

	if err := h.deviceService.TrustDeviceByDeviceID(c.Request.Context(), userID, deviceID, trustDuration); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "device trusted",
	})
}

// UntrustDevice 取消设备信任状态
// @Summary 取消设备信任
// @Description 取消设备的信任状态
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response "取消成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/trust [delete]
func (h *DeviceHandler) UntrustDevice(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid device id"})
		return
	}

	if err := h.deviceService.UntrustDevice(c.Request.Context(), id); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "device untrusted",
	})
}

// GetMyTrustedDevices 获取我的信任设备列表
// @Summary 获取信任设备列表
// @Description 获取当前用户的信任设备列表
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Device} "信任设备列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/trusted [get]
func (h *DeviceHandler) GetMyTrustedDevices(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	devices, err := h.deviceService.GetTrustedDevices(c.Request.Context(), userID)
	if err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data":    devices,
	})
}

// LogoutAllOtherDevices 登出所有其他设备
// @Summary 登出其他设备
// @Description 登出当前用户除指定设备外的所有其他设备
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param X-Device-ID header string true "当前设备ID"
// @Success 200 {object} Response "登出成功"
// @Failure 400 {object} Response "无效的设备ID"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/logout-others [post]
func (h *DeviceHandler) LogoutAllOtherDevices(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	// 从请求中获取当前设备ID
	currentDeviceIDStr := c.GetHeader("X-Device-ID")
	currentDeviceID, err := strconv.ParseInt(currentDeviceIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid current device id"})
		return
	}

	if err := h.deviceService.LogoutAllOtherDevices(c.Request.Context(), userID, currentDeviceID); err != nil {
		handleError(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "all other devices logged out",
	})
}

// parseDuration 解析duration字符串，如 "30d" -> 30天的time.Duration
func parseDuration(s string) time.Duration {
	if s == "" {
		return 0
	}
	// 简单实现，支持 d(天)和h(小时)
	var d int
	var h int
	_, _ = d, h
	switch s[len(s)-1] {
	case 'd':
		d = 1
		_, _ = fmt.Sscanf(s[:len(s)-1], "%d", &d)
		return time.Duration(d) * 24 * time.Hour
	case 'h':
		_, _ = fmt.Sscanf(s[:len(s)-1], "%d", &h)
		return time.Duration(h) * time.Hour
	}
	return 0
}
