package service

import (
	"archive/zip"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gorm.io/gorm"
)

// BackupService 备份服务
type BackupService struct {
	db *gorm.DB
}

// NewBackupService 创建备份服务
func NewBackupService(db *gorm.DB) *BackupService {
	return &BackupService{
		db: db,
	}
}

// CreateBackup 创建系统备份
func (s *BackupService) CreateBackup(ctx context.Context, backupFile string) error {
	// 1. 导出数据库数据到临时文件
	tempDir := filepath.Join("data", "temp_backup")
	if err := os.MkdirAll(tempDir, 0755); err != nil {
		return fmt.Errorf("创建临时目录失败：%w", err)
	}
	defer os.RemoveAll(tempDir)

	// 导出数据库
	dbDumpFile := filepath.Join(tempDir, "meshray.sql")
	if err := s.dumpDatabase(dbDumpFile); err != nil {
		return fmt.Errorf("导出数据库失败：%w", err)
	}

	// 2. 备份配置文件
	configFiles := []string{
		"config.yaml",
	}

	for _, configFile := range configFiles {
		if _, err := os.Stat(configFile); err == nil {
			// 复制配置文件到临时目录
			src, err := os.Open(configFile)
			if err != nil {
				return fmt.Errorf("打开配置文件失败：%w", err)
			}
			defer src.Close()

			dstPath := filepath.Join(tempDir, filepath.Base(configFile))
			dst, err := os.Create(dstPath)
			if err != nil {
				return fmt.Errorf("创建配置文件副本失败：%w", err)
			}
			defer dst.Close()

			if _, err := io.Copy(dst, src); err != nil {
				return fmt.Errorf("复制配置文件失败：%w", err)
			}
		}
	}

	// 3. 打包成 zip 文件
	if err := s.createZipFile(backupFile, tempDir); err != nil {
		return fmt.Errorf("创建压缩文件失败：%w", err)
	}

	return nil
}

// RestoreBackup 恢复备份
func (s *BackupService) RestoreBackup(ctx context.Context, backupFile string) error {
	// 1. 解压备份文件
	tempDir := filepath.Join("data", "temp_restore")
	if err := os.MkdirAll(tempDir, 0755); err != nil {
		return fmt.Errorf("创建临时目录失败：%w", err)
	}
	defer os.RemoveAll(tempDir)

	if err := s.extractZipFile(backupFile, tempDir); err != nil {
		return fmt.Errorf("解压备份文件失败：%w", err)
	}

	// 2. 恢复数据库
	dbDumpFile := filepath.Join(tempDir, "meshray.sql")
	if _, err := os.Stat(dbDumpFile); err == nil {
		if err := s.restoreDatabase(dbDumpFile); err != nil {
			return fmt.Errorf("恢复数据库失败：%w", err)
		}
	}

	// 3. 恢复配置文件
	configFile := filepath.Join(tempDir, "config.yaml")
	if _, err := os.Stat(configFile); err == nil {
		// 备份当前配置
		if _, err := os.Stat("config.yaml"); err == nil {
			os.Rename("config.yaml", "config.yaml.bak."+time.Now().Format("20060102_150405"))
		}

		// 复制新配置
		src, err := os.Open(configFile)
		if err != nil {
			return fmt.Errorf("打开备份配置文件失败：%w", err)
		}
		defer src.Close()

		dst, err := os.Create("config.yaml")
		if err != nil {
			return fmt.Errorf("创建配置文件失败：%w", err)
		}
		defer dst.Close()

		if _, err := io.Copy(dst, src); err != nil {
			return fmt.Errorf("复制配置文件失败：%w", err)
		}
	}

	return nil
}

// dumpDatabase 导出数据库到 SQL 文件
func (s *BackupService) dumpDatabase(outputFile string) error {
	// 使用 SQLite 的 dump 功能
	// 通过 gorm 执行 PRAGMA 和查询来导出所有表结构和数据

	file, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer file.Close()

	// 写入注释头
	file.WriteString("-- MeshRay Database Backup\n")
	file.WriteString(fmt.Sprintf("-- Generated at: %s\n\n", time.Now().Format(time.RFC3339)))

	// 获取所有表名
	var tables []string
	if err := s.db.Raw("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").Scan(&tables).Error; err != nil {
		return err
	}

	// 导出每个表
	for _, table := range tables {
		// 导出表结构
		var createSQL string
		if err := s.db.Raw(fmt.Sprintf("SELECT sql FROM sqlite_master WHERE type='table' AND name='%s'", table)).Scan(&createSQL).Error; err != nil {
			continue
		}

		file.WriteString(fmt.Sprintf("-- Table structure for table `%s`\n", table))
		file.WriteString("DROP TABLE IF EXISTS `" + table + "`;\n")
		file.WriteString(createSQL + ";\n\n")

		// 导出表数据
		var rows []map[string]interface{}
		if err := s.db.Table(table).Find(&rows).Error; err != nil {
			continue
		}

		if len(rows) > 0 {
			file.WriteString(fmt.Sprintf("-- Data for table `%s`\n", table))
			file.WriteString("INSERT INTO `" + table + "` VALUES\n")

			for i, row := range rows {
				values := make([]string, 0)
				for _, v := range row {
					if v == nil {
						values = append(values, "NULL")
					} else {
						values = append(values, fmt.Sprintf("'%v'", v))
					}
				}

				if i < len(rows)-1 {
					file.WriteString("(" + strings.Join(values, ",") + "),\n")
				} else {
					file.WriteString("(" + strings.Join(values, ",") + ");\n\n")
				}
			}
		}
	}

	return nil
}

// restoreDatabase 从 SQL 文件恢复数据库
func (s *BackupService) restoreDatabase(inputFile string) error {
	// 读取 SQL 文件
	content, err := os.ReadFile(inputFile)
	if err != nil {
		return err
	}

	// 简单实现：执行 SQL 语句
	// 生产环境应该使用 SQLite 命令行工具或更完善的 SQL 解析器
	queries := strings.Split(string(content), ";")

	for _, query := range queries {
		query = strings.TrimSpace(query)
		if query == "" || strings.HasPrefix(query, "--") {
			continue
		}

		// 执行 SQL 语句
		if err := s.db.Exec(query).Error; err != nil {
			// 忽略错误（因为可能遇到 DROP TABLE 时表不存在）
			continue
		}
	}

	return nil
}

// createZipFile 创建 ZIP 压缩文件
func (s *BackupService) createZipFile(zipFile, sourceDir string) error {
	file, err := os.Create(zipFile)
	if err != nil {
		return err
	}
	defer file.Close()

	writer := zip.NewWriter(file)
	defer writer.Close()

	return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录本身
		if info.IsDir() {
			return nil
		}

		// 创建 ZIP 中的文件头
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name, _ = filepath.Rel(sourceDir, path)
		header.Method = zip.Deflate

		f, err := writer.CreateHeader(header)
		if err != nil {
			return err
		}

		// 读取源文件并写入 ZIP
		srcFile, err := os.Open(path)
		if err != nil {
			return err
		}
		defer srcFile.Close()

		_, err = io.Copy(f, srcFile)
		return err
	})
}

// extractZipFile 解压 ZIP 文件
func (s *BackupService) extractZipFile(zipFile, destDir string) error {
	reader, err := zip.OpenReader(zipFile)
	if err != nil {
		return err
	}
	defer reader.Close()

	for _, file := range reader.File {
		path := filepath.Join(destDir, file.Name)

		// 如果是目录，创建目录
		if file.FileInfo().IsDir() {
			os.MkdirAll(path, 0755)
			continue
		}

		// 创建父目录
		if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
			return err
		}

		// 解压文件
		srcFile, err := file.Open()
		if err != nil {
			return err
		}
		defer srcFile.Close()

		dstFile, err := os.Create(path)
		if err != nil {
			return err
		}
		defer dstFile.Close()

		_, err = io.Copy(dstFile, srcFile)
		if err != nil {
			return err
		}
	}

	return nil
}
