package admin

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/middleware"
	"verification-platform-backend/internal/model"
	"verification-platform-backend/internal/service"
	"verification-platform-backend/pkg/response"

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

func SetupCloudRoutes(r *gin.RouterGroup) {
	cloudConstants := r.Group("/cloud-constants")
	{
		cloudConstants.GET("", handleGetCloudConstants)
		cloudConstants.GET("/:id", handleGetCloudConstant)
		cloudConstants.GET("/:id/download", handleDownloadCloudConstant)
		cloudConstants.POST("", handleCreateCloudConstant)
		cloudConstants.POST("/upload", handleUploadCloudConstant)
		cloudConstants.PUT("/:id", handleUpdateCloudConstant)
		cloudConstants.DELETE("/:id", handleDeleteCloudConstant)
	}

	cloudVariables := r.Group("/cloud-variables")
	{
		cloudVariables.GET("", handleGetCloudVariables)
		cloudVariables.GET("/:id", handleGetCloudVariable)
		cloudVariables.GET("/:id/download", handleDownloadCloudVariable)
		cloudVariables.POST("", handleCreateCloudVariable)
		cloudVariables.POST("/upload", handleUploadCloudVariable)
		cloudVariables.PUT("/:id", handleUpdateCloudVariable)
		cloudVariables.DELETE("/:id", handleDeleteCloudVariable)
		cloudVariables.GET("/:id/records", handleGetCloudVariableRecords)
		cloudVariables.DELETE("/:id/records", handleDeleteCloudVariableRecords)
	}
}

func handleGetCloudConstants(c *gin.Context) {
	userID := c.GetUint("user_id")
	appID := c.Query("app_id")

	var constants []model.CloudConstant
	query := database.DB.Where("user_id = ?", userID)
	if appID != "" {
		query = query.Where("app_id = ?", appID)
	}
	if err := query.Find(&constants).Error; err != nil {
		response.Error(c, 500, "获取云端常量失败")
		return
	}
	response.Success(c, gin.H{
		"constants": constants,
		"total":     len(constants),
	})
}

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

	var constant model.CloudConstant
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&constant).Error; err != nil {
		response.Error(c, 404, "云端常量不存在")
		return
	}

	response.Success(c, constant)
}

func handleCreateCloudConstant(c *gin.Context) {
	userID := c.GetUint("user_id")

	var req struct {
		AppID       uint   `json:"app_id"`
		Key         string `json:"key"`
		Value       string `json:"value"`
		VarType     string `json:"var_type"`
		Description string `json:"description"`
		Status      string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if req.Key == "" {
		response.Error(c, 400, "变量名不能为空")
		return
	}

	if req.Status != "active" && req.Status != "inactive" {
		req.Status = "active"
	}

	if req.VarType == "" {
		req.VarType = "string"
	}

	constant := model.CloudConstant{
		UserID:      userID,
		AppID:       &req.AppID,
		Key:         req.Key,
		Value:       req.Value,
		VarType:     req.VarType,
		Description: req.Description,
		Status:      req.Status,
	}

	if err := database.DB.Create(&constant).Error; err != nil {
		response.Error(c, 500, "创建云端常量失败")
		return
	}

	service.LogOperation(c, "create", "cloud_constant", &constant.ID, fmt.Sprintf("创建云端常量: %s", constant.Key), nil)

	response.Success(c, constant)
}

func handleUpdateCloudConstant(c *gin.Context) {
	userID := c.GetUint("user_id")

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

	id := c.Param("id")
	var constant model.CloudConstant
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&constant).Error; err != nil {
		response.Error(c, 404, "云端常量不存在")
		return
	}

	constant.Key = req.Key
	constant.Value = req.Value
	constant.VarType = req.VarType
	constant.Description = req.Description
	if req.Status == "active" || req.Status == "inactive" {
		constant.Status = req.Status
	}

	if err := database.DB.Save(&constant).Error; err != nil {
		response.Error(c, 500, "更新云端常量失败")
		return
	}

	service.LogOperation(c, "update", "cloud_constant", &constant.ID, fmt.Sprintf("更新云端常量: %s", constant.Key), nil)

	response.Success(c, constant)
}

func handleDeleteCloudConstant(c *gin.Context) {
	userID := c.GetUint("user_id")

	id := c.Param("id")

	var constant model.CloudConstant
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&constant).Error; err != nil {
		response.Error(c, 404, "云端常量不存在")
		return
	}

	if constant.VarType == "binary" && constant.FilePath != "" {
		if err := middleware.UpdateStorageUsed(userID, constant.FileSize, "delete"); err != nil {
			fmt.Printf("更新存储使用量失败: %v\n", err)
		}
		filePath := strings.TrimPrefix(constant.FilePath, "/")
		if _, err := os.Stat(filePath); err == nil {
			os.Remove(filePath)
		}
	}

	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).Delete(&model.CloudConstant{}).Error; err != nil {
		response.Error(c, 500, "删除云端常量失败")
		return
	}

	service.LogOperation(c, "delete", "cloud_constant", &constant.ID, fmt.Sprintf("删除云端常量: %s", constant.Key), nil)

	response.Success(c, nil)
}

func handleUploadCloudConstant(c *gin.Context) {
	userID := c.GetUint("user_id")

	file, header, err := c.Request.FormFile("file")
	if err != nil {
		response.Error(c, 400, "请选择要上传的文件")
		return
	}
	defer file.Close()

	appIDStr := c.PostForm("app_id")
	key := c.PostForm("key")
	description := c.PostForm("description")
	status := c.PostForm("status")

	if appIDStr == "" {
		response.Error(c, 400, "请选择应用")
		return
	}

	if key == "" {
		response.Error(c, 400, "请输入变量名")
		return
	}

	var appID uint
	fmt.Sscanf(appIDStr, "%d", &appID)

	if status != "active" && status != "inactive" {
		status = "active"
	}

	var user model.User
	if err := database.DB.First(&user, userID).Error; err != nil {
		response.Error(c, 500, "获取用户信息失败")
		return
	}

	if user.CurrentPackageID != nil {
		var permission model.PackagePermission
		if err := database.DB.Where("package_id = ?", user.CurrentPackageID).First(&permission).Error; err == nil {
			maxStorageBytes := int64(permission.MaxStorage) * 1024 * 1024
			if user.StorageUsed+header.Size > maxStorageBytes {
				usedMB := float64(user.StorageUsed) / 1024 / 1024
				maxMB := float64(permission.MaxStorage)
				response.Error(c, 403, fmt.Sprintf("存储空间不足，已使用 %.2f MB / %.2f MB", usedMB, maxMB))
				return
			}
		}
	}

	uploadDir := "uploads/cloud-files"
	if err := os.MkdirAll(uploadDir, 0755); err != nil {
		response.Error(c, 500, "创建上传目录失败")
		return
	}

	ext := filepath.Ext(header.Filename)
	filename := fmt.Sprintf("%d_%d%s", userID, time.Now().UnixNano(), ext)
	filePath := filepath.Join(uploadDir, filename)

	dst, err := os.Create(filePath)
	if err != nil {
		response.Error(c, 500, "创建文件失败")
		return
	}
	defer dst.Close()

	hash := md5.New()
	multiWriter := io.MultiWriter(dst, hash)
	if _, err := io.Copy(multiWriter, file); err != nil {
		response.Error(c, 500, "保存文件失败")
		return
	}
	fileMD5 := hex.EncodeToString(hash.Sum(nil))

	fileURL := "/uploads/cloud-files/" + filename

	mimeType := header.Header.Get("Content-Type")
	if mimeType == "" {
		mimeType = "application/octet-stream"
	}

	constant := model.CloudConstant{
		UserID:       userID,
		AppID:        &appID,
		Key:          key,
		Value:        fileURL,
		VarType:      "binary",
		FilePath:     fileURL,
		FileSize:     header.Size,
		MimeType:     mimeType,
		OriginalName: header.Filename,
		FileMD5:      fileMD5,
		Description:  description,
		Status:       status,
	}

	if err := database.DB.Create(&constant).Error; err != nil {
		os.Remove(filePath)
		response.Error(c, 500, "创建云端常量失败")
		return
	}

	if err := middleware.UpdateStorageUsed(userID, header.Size, "upload"); err != nil {
		fmt.Printf("更新存储使用量失败: %v\n", err)
	}

	usage := model.StorageUsage{
		UserID:        userID,
		ApplicationID: &appID,
		ResourceType:  "cloud_constant",
		ResourceID:    constant.ID,
		FileName:      header.Filename,
		FileSize:      header.Size,
		Action:        "upload",
		CreatedAt:     time.Now(),
	}
	database.DB.Create(&usage)

	service.LogOperation(c, "create", "cloud_constant", &constant.ID, fmt.Sprintf("上传文件常量: %s", constant.Key), nil)

	response.Success(c, constant)
}

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

	var constant model.CloudConstant
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&constant).Error; err != nil {
		response.Error(c, 404, "云端常量不存在")
		return
	}

	if constant.VarType != "binary" || constant.FilePath == "" {
		response.Error(c, 400, "该常量不是文件类型")
		return
	}

	filePath := constant.FilePath
	if strings.HasPrefix(filePath, "/") {
		filePath = filePath[1:]
	}

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		response.Error(c, 404, "文件不存在")
		return
	}

	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", constant.OriginalName))
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "must-revalidate")
	c.Header("Pragma", "public")
	c.FileAttachment(filePath, constant.OriginalName)
}

func handleGetCloudVariables(c *gin.Context) {
	userID := c.GetUint("user_id")
	appID := c.Query("app_id")

	var variables []model.CloudVariable
	query := database.DB.Where("user_id = ?", userID)
	if appID != "" {
		query = query.Where("app_id = ?", appID)
	}
	if err := query.Find(&variables).Error; err != nil {
		response.Error(c, 500, "获取云端变量失败")
		return
	}
	response.Success(c, gin.H{
		"variables": variables,
		"total":     len(variables),
	})
}

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

	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	response.Success(c, variable)
}

func handleCreateCloudVariable(c *gin.Context) {
	userID := c.GetUint("user_id")

	var req struct {
		AppID           uint   `json:"app_id"`
		Key             string `json:"key"`
		DefaultValue    string `json:"default_value"`
		VarType         string `json:"var_type"`
		MaxRecords      int    `json:"max_records"`
		Scope           string `json:"scope"`
		WritePermission string `json:"write_permission"`
		Description     string `json:"description"`
		Status          string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if req.Key == "" {
		response.Error(c, 400, "变量名不能为空")
		return
	}

	if req.Scope != "app" && req.Scope != "user" {
		req.Scope = "app"
	}

	if req.WritePermission != "admin" && req.WritePermission != "user" && req.WritePermission != "app_user" {
		req.WritePermission = "admin"
	}

	if req.Status != "active" && req.Status != "inactive" {
		req.Status = "active"
	}

	if req.VarType == "" {
		req.VarType = "string"
	}

	variable := model.CloudVariable{
		UserID:          userID,
		AppID:           &req.AppID,
		Key:             req.Key,
		DefaultValue:    req.DefaultValue,
		VarType:         req.VarType,
		MaxRecords:      req.MaxRecords,
		Scope:           req.Scope,
		WritePermission: req.WritePermission,
		Description:     req.Description,
		Status:          req.Status,
	}

	if err := database.DB.Create(&variable).Error; err != nil {
		response.Error(c, 500, "创建云端变量失败")
		return
	}

	response.Success(c, variable)
}

func handleUpdateCloudVariable(c *gin.Context) {
	userID := c.GetUint("user_id")

	var req struct {
		Key             string `json:"key"`
		DefaultValue    string `json:"default_value"`
		VarType         string `json:"var_type"`
		MaxRecords      int    `json:"max_records"`
		WritePermission string `json:"write_permission"`
		Description     string `json:"description"`
		Status          string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	id := c.Param("id")
	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	variable.Key = req.Key
	variable.DefaultValue = req.DefaultValue
	variable.VarType = req.VarType
	variable.MaxRecords = req.MaxRecords
	if req.WritePermission == "admin" || req.WritePermission == "user" || req.WritePermission == "app_user" {
		variable.WritePermission = req.WritePermission
	}
	variable.Description = req.Description
	if req.Status == "active" || req.Status == "inactive" {
		variable.Status = req.Status
	}

	if err := database.DB.Save(&variable).Error; err != nil {
		response.Error(c, 500, "更新云端变量失败")
		return
	}

	response.Success(c, variable)
}

func handleDeleteCloudVariable(c *gin.Context) {
	userID := c.GetUint("user_id")

	id := c.Param("id")

	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	if variable.VarType == "binary" && variable.FilePath != "" {
		if err := middleware.UpdateStorageUsed(userID, variable.FileSize, "delete"); err != nil {
			fmt.Printf("更新存储使用量失败: %v\n", err)
		}
		filePath := strings.TrimPrefix(variable.FilePath, "/")
		if _, err := os.Stat(filePath); err == nil {
			os.Remove(filePath)
		}
	}

	if err := database.DB.Delete(&variable).Error; err != nil {
		response.Error(c, 500, "删除云端变量失败")
		return
	}
	response.Success(c, nil)
}

func handleUploadCloudVariable(c *gin.Context) {
	userID := c.GetUint("user_id")

	file, header, err := c.Request.FormFile("file")
	if err != nil {
		response.Error(c, 400, "请选择要上传的文件")
		return
	}
	defer file.Close()

	appIDStr := c.PostForm("app_id")
	key := c.PostForm("key")
	description := c.PostForm("description")
	status := c.PostForm("status")
	scope := c.PostForm("scope")
	writePermission := c.PostForm("write_permission")

	if appIDStr == "" {
		response.Error(c, 400, "请选择应用")
		return
	}

	if key == "" {
		response.Error(c, 400, "请输入变量名")
		return
	}

	var appID uint
	fmt.Sscanf(appIDStr, "%d", &appID)

	if status != "active" && status != "inactive" {
		status = "active"
	}

	if scope != "app" && scope != "user" {
		scope = "app"
	}

	if writePermission != "admin" && writePermission != "user" {
		writePermission = "admin"
	}

	var user model.User
	if err := database.DB.First(&user, userID).Error; err != nil {
		response.Error(c, 500, "获取用户信息失败")
		return
	}

	if user.CurrentPackageID != nil {
		var permission model.PackagePermission
		if err := database.DB.Where("package_id = ?", user.CurrentPackageID).First(&permission).Error; err == nil {
			maxStorageBytes := int64(permission.MaxStorage) * 1024 * 1024
			if user.StorageUsed+header.Size > maxStorageBytes {
				usedMB := float64(user.StorageUsed) / 1024 / 1024
				maxMB := float64(permission.MaxStorage)
				response.Error(c, 403, fmt.Sprintf("存储空间不足，已使用 %.2f MB / %.2f MB", usedMB, maxMB))
				return
			}
		}
	}

	uploadDir := "uploads/cloud-files"
	if err := os.MkdirAll(uploadDir, 0755); err != nil {
		response.Error(c, 500, "创建上传目录失败")
		return
	}

	ext := filepath.Ext(header.Filename)
	filename := fmt.Sprintf("%d_%d%s", userID, time.Now().UnixNano(), ext)
	filePath := filepath.Join(uploadDir, filename)

	dst, err := os.Create(filePath)
	if err != nil {
		response.Error(c, 500, "创建文件失败")
		return
	}
	defer dst.Close()

	hash := md5.New()
	multiWriter := io.MultiWriter(dst, hash)
	if _, err := io.Copy(multiWriter, file); err != nil {
		response.Error(c, 500, "保存文件失败")
		return
	}
	fileMD5 := hex.EncodeToString(hash.Sum(nil))

	fileURL := "/uploads/cloud-files/" + filename

	mimeType := header.Header.Get("Content-Type")
	if mimeType == "" {
		mimeType = "application/octet-stream"
	}

	variable := model.CloudVariable{
		UserID:          userID,
		AppID:           &appID,
		Key:             key,
		DefaultValue:    fileURL,
		VarType:         "binary",
		FilePath:        fileURL,
		FileSize:        header.Size,
		MimeType:        mimeType,
		OriginalName:    header.Filename,
		FileMD5:         fileMD5,
		Scope:           scope,
		WritePermission: writePermission,
		Description:     description,
		Status:          status,
	}

	if err := database.DB.Create(&variable).Error; err != nil {
		os.Remove(filePath)
		response.Error(c, 500, "创建云端变量失败")
		return
	}

	if err := middleware.UpdateStorageUsed(userID, header.Size, "upload"); err != nil {
		fmt.Printf("更新存储使用量失败: %v\n", err)
	}

	usage := model.StorageUsage{
		UserID:        userID,
		ApplicationID: &appID,
		ResourceType:  "cloud_variable",
		ResourceID:    variable.ID,
		FileName:      header.Filename,
		FileSize:      header.Size,
		Action:        "upload",
		CreatedAt:     time.Now(),
	}
	database.DB.Create(&usage)

	service.LogOperation(c, "create", "cloud_variable", &variable.ID, fmt.Sprintf("上传文件变量: %s", variable.Key), nil)

	response.Success(c, variable)
}

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

	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	if variable.VarType != "binary" || variable.FilePath == "" {
		response.Error(c, 400, "该变量不是文件类型")
		return
	}

	filePath := variable.FilePath
	if strings.HasPrefix(filePath, "/") {
		filePath = filePath[1:]
	}

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		response.Error(c, 404, "文件不存在")
		return
	}

	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", variable.OriginalName))
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "must-revalidate")
	c.Header("Pragma", "public")
	c.FileAttachment(filePath, variable.OriginalName)
}

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

	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	if variable.VarType != "stream" {
		response.Error(c, 400, "该变量不是记录类型")
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 20
	}

	userIDFilter := c.Query("user_id")
	startDate := c.Query("start_date")
	endDate := c.Query("end_date")

	var total int64
	query := database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID)
	if userIDFilter != "" {
		query = query.Where("app_user_id = ?", userIDFilter)
	}
	if startDate != "" {
		query = query.Where("created_at >= ?", startDate+" 00:00:00")
	}
	if endDate != "" {
		query = query.Where("created_at <= ?", endDate+" 23:59:59")
	}
	query.Count(&total)

	var records []model.CloudVariableRecord
	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&records).Error; err != nil {
		response.Error(c, 500, "获取记录失败")
		return
	}

	result := make([]gin.H, len(records))
	for i, r := range records {
		var data map[string]interface{}
		json.Unmarshal([]byte(r.Data), &data)
		record := gin.H{
			"id":         r.ID,
			"data":       data,
			"created_at": r.CreatedAt,
		}
		if r.AppUserID != nil {
			record["user_id"] = r.AppUserID
			var appUser model.AppUser
			if err := database.DB.Select("id, username").First(&appUser, *r.AppUserID).Error; err == nil {
				record["user"] = gin.H{
					"id":       appUser.ID,
					"username": appUser.Username,
				}
			}
		}
		result[i] = record
	}

	response.Success(c, gin.H{
		"records":     result,
		"total":       total,
		"page":        page,
		"page_size":   pageSize,
		"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
	})
}

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

	var variable model.CloudVariable
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&variable).Error; err != nil {
		response.Error(c, 404, "云端变量不存在")
		return
	}

	if variable.VarType != "stream" {
		response.Error(c, 400, "该变量不是记录类型")
		return
	}

	var req struct {
		IDs    []uint `json:"ids"`
		Before string `json:"before"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if len(req.IDs) > 0 {
		if err := database.DB.Where("cloud_variable_id = ? AND id IN ?", variable.ID, req.IDs).Delete(&model.CloudVariableRecord{}).Error; err != nil {
			response.Error(c, 500, "删除记录失败")
			return
		}
	} else if req.Before != "" {
		if err := database.DB.Where("cloud_variable_id = ? AND created_at < ?", variable.ID, req.Before).Delete(&model.CloudVariableRecord{}).Error; err != nil {
			response.Error(c, 500, "删除记录失败")
			return
		}
	} else {
		response.Error(c, 400, "请指定要删除的记录")
		return
	}

	response.Success(c, nil)
}
