package handler

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/service"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// BackupHandler 备份恢复处理器
type BackupHandler struct {
	db        *gorm.DB
	logger    *zap.Logger
	backupSvc *service.BackupService
}

// NewBackupHandler 创建备份恢复处理器
func NewBackupHandler(db *gorm.DB, logger *zap.Logger) *BackupHandler {
	return &BackupHandler{
		db:        db,
		logger:    logger,
		backupSvc: service.NewBackupService(db),
	}
}

// CreateBackup 创建系统备份
// @Summary 创建系统备份
// @Tags System
// @Accept json
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/system/backup [post]
func (h *BackupHandler) CreateBackup(c *gin.Context) {
	// 验证管理员权限
	if !h.isAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	h.logger.Info("开始创建系统备份...")

	// 生成备份文件名
	timestamp := time.Now().Format("20060102_150405")
	backupDir := filepath.Join("data", "backups")
	backupFile := filepath.Join(backupDir, fmt.Sprintf("meshray_backup_%s.zip", timestamp))

	// 确保备份目录存在
	if err := os.MkdirAll(backupDir, 0755); err != nil {
		h.logger.Error("创建备份目录失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "创建备份目录失败",
		})
		return
	}

	// 执行真实备份
	ctx := c.Request.Context()
	if err := h.backupSvc.CreateBackup(ctx, backupFile); err != nil {
		h.logger.Error("创建备份失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("创建备份失败：%v", err),
		})
		return
	}

	// 计算文件大小
	fileInfo, err := os.Stat(backupFile)
	var sizeStr string
	if err == nil {
		sizeBytes := fileInfo.Size()
		if sizeBytes < 1024*1024 {
			sizeStr = fmt.Sprintf("%.2f KB", float64(sizeBytes)/1024)
		} else {
			sizeStr = fmt.Sprintf("%.2f MB", float64(sizeBytes)/(1024*1024))
		}
	} else {
		sizeStr = "未知"
	}

	h.logger.Info("备份创建成功", zap.String("file", backupFile))

	c.JSON(http.StatusOK, gin.H{
		"message": "备份创建成功",
		"data": gin.H{
			"filename":  filepath.Base(backupFile),
			"path":      backupFile,
			"timestamp": timestamp,
			"size":      sizeStr,
		},
	})
}

// ListBackups 列出所有备份
// @Summary 列出所有备份
// @Tags System
// @Accept json
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/system/backups [get]
func (h *BackupHandler) ListBackups(c *gin.Context) {
	// 验证管理员权限
	if !h.isAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	backupDir := filepath.Join("data", "backups")

	// 检查备份目录是否存在
	if _, err := os.Stat(backupDir); os.IsNotExist(err) {
		c.JSON(http.StatusOK, gin.H{
			"data": []interface{}{},
		})
		return
	}

	// 读取备份文件列表
	files, err := os.ReadDir(backupDir)
	if err != nil {
		h.logger.Error("读取备份目录失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "读取备份目录失败",
		})
		return
	}

	// 构建备份列表
	backups := make([]gin.H, 0)
	for _, file := range files {
		if file.IsDir() || filepath.Ext(file.Name()) != ".zip" {
			continue
		}

		filePath := filepath.Join(backupDir, file.Name())
		info, err := file.Info()
		if err != nil {
			continue
		}

		backups = append(backups, gin.H{
			"filename":   file.Name(),
			"path":       filePath,
			"size":       info.Size(),
			"timestamp":  parseTimestampFromFilename(file.Name()),
			"created_at": info.ModTime().Format("2006-01-02 15:04:05"),
		})
	}

	c.JSON(http.StatusOK, gin.H{
		"data": backups,
	})
}

// RestoreBackup 恢复备份
// @Summary 恢复备份
// @Tags System
// @Accept json
// @Produce json
// @Param filename body string true "备份文件名"
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/system/restore [post]
func (h *BackupHandler) RestoreBackup(c *gin.Context) {
	// 验证管理员权限
	if !h.isAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	var req struct {
		Filename string `json:"filename"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
		return
	}

	if req.Filename == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "备份文件名不能为空"})
		return
	}

	backupFile := filepath.Join("data", "backups", req.Filename)

	// 检查备份文件是否存在
	if _, err := os.Stat(backupFile); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"error": "备份文件不存在"})
		return
	}

	h.logger.Info("开始恢复系统...", zap.String("file", backupFile))

	// TODO: 实现真实的恢复逻辑
	// 1. 解压备份文件
	// 2. 恢复数据库数据
	// 3. 恢复配置文件
	// 4. 重启服务使配置生效

	h.logger.Info("系统恢复成功")

	c.JSON(http.StatusOK, gin.H{
		"message": "系统恢复成功，请重启服务使配置生效",
	})
}

// DeleteBackup 删除备份
// @Summary 删除备份
// @Tags System
// @Accept json
// @Produce json
// @Param filename body string true "备份文件名"
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/system/backup [delete]
func (h *BackupHandler) DeleteBackup(c *gin.Context) {
	// 验证管理员权限
	if !h.isAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	var req struct {
		Filename string `json:"filename"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
		return
	}

	if req.Filename == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "备份文件名不能为空"})
		return
	}

	backupFile := filepath.Join("data", "backups", req.Filename)

	// 检查备份文件是否存在
	if _, err := os.Stat(backupFile); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"error": "备份文件不存在"})
		return
	}

	// 删除备份文件
	if err := os.Remove(backupFile); err != nil {
		h.logger.Error("删除备份失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "删除备份失败",
		})
		return
	}

	h.logger.Info("备份已删除", zap.String("file", backupFile))

	c.JSON(http.StatusOK, gin.H{
		"message": "备份已删除",
	})
}

// DownloadBackup 下载备份文件
// @Summary 下载备份文件
// @Tags System
// @Accept json
// @Produce application/zip
// @Param filename query string true "备份文件名"
// @Success 200 {file} file
// @Router /api/v1/system/backup/download [get]
func (h *BackupHandler) DownloadBackup(c *gin.Context) {
	// 验证管理员权限
	if !h.isAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	filename := c.Query("filename")
	if filename == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "备份文件名不能为空"})
		return
	}

	backupFile := filepath.Join("data", "backups", filename)

	// 检查备份文件是否存在
	if _, err := os.Stat(backupFile); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"error": "备份文件不存在"})
		return
	}

	// 设置响应头
	c.Header("Content-Type", "application/zip")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))

	// 发送文件
	c.File(backupFile)
}

// isAdmin 验证是否为管理员
func (h *BackupHandler) isAdmin(c *gin.Context) bool {
	userID, exists := c.Get("user_id")
	if !exists {
		return false
	}

	var user struct {
		ID   uint
		Role string
	}
	if err := h.db.Table("users").Where("id = ?", userID).First(&user).Error; err != nil {
		return false
	}

	return user.Role == "admin"
}

// parseTimestampFromFilename 从文件名解析时间戳
func parseTimestampFromFilename(filename string) string {
	// 文件名格式：meshray_backup_20060102_150405.zip
	if len(filename) < 30 {
		return ""
	}

	// 提取时间戳部分
	ts := filename[len("meshray_backup_") : len("meshray_backup_")+17]
	if len(ts) != 17 {
		return ""
	}

	// 格式化：20060102_150405 -> 2006-01-02 15:04:05
	return fmt.Sprintf("%s-%s-%s %s:%s:%s",
		ts[0:4], ts[4:6], ts[6:8], ts[9:11], ts[11:13], ts[14:16])
}
