package backup_export_log

import (
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
	"time"

	"be.ems/src/framework/cron"
	"be.ems/src/framework/i18n"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/date"
	"be.ems/src/framework/utils/file"
	neDataService "be.ems/src/modules/ne_data/service"
	systemModel "be.ems/src/modules/system/model"
	systemService "be.ems/src/modules/system/service"
)

var NewProcessor = &BackupExportLogProcessor{
	count:              0,
	backupService:      neDataService.NewBackup,
	sysLogLoginService: systemService.NewSysLogLogin,
	sysOperateService:  systemService.NewSysLogOperate,
}

// BackupExportLog 队列任务处理
type BackupExportLogProcessor struct {
	count              int                          // 执行次数
	backupService      *neDataService.Backup        // 备份相关服务
	sysLogLoginService *systemService.SysLogLogin   // 系统登录日志服务
	sysOperateService  *systemService.SysLogOperate // 系统操作日志服务
}

func (s *BackupExportLogProcessor) Execute(data any) (any, error) {
	s.count++ // 执行次数加一
	options := data.(cron.JobData)
	sysJob := options.SysJob
	logger.Infof("重复:%v 任务ID:%d  执行次数:%d", options.Repeat, sysJob.JobId, s.count)
	// 返回结果，用于记录执行结果
	result := map[string]any{
		"count": s.count,
	}

	var params struct {
		DataType []string `json:"dataType"` // 类型支持 operate/login
		FileType string   `json:"fileType"` // 文件类型 csv/xlsx
		Hour     int      `json:"hour"`     // 数据时间从任务执行时间前的小时数
	}
	if err := json.Unmarshal([]byte(sysJob.TargetParams), &params); err != nil {
		return nil, err
	}
	if !(params.FileType == "csv" || params.FileType == "xlsx") {
		return nil, fmt.Errorf("file type error, only support csv,xlsx")
	}

	for _, v := range params.DataType {
		switch v {
		case "operate":
			result[v] = s.exportOperate(params.Hour, params.FileType)
		case "login":
			result[v] = s.exportLogin(params.Hour, params.FileType)
		}
	}

	// 返回结果，用于记录执行结果
	return result, nil
}

// exportOperate 导出系统操作日志数据
func (s BackupExportLogProcessor) exportOperate(hour int, fileType string) string {
	// 前 hour 小时
	now := time.Now()
	end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
	start := end.Add(-time.Duration(hour) * time.Hour)

	language := "en"
	query := map[string]string{
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	}
	rows, total := s.sysOperateService.FindByPage(query, "")
	if total == 0 {
		return "no data"
	}

	// 闭包函数处理多语言
	converI18n := func(language string, arr *[]systemModel.SysLogOperate) {
		for i := range *arr {
			(*arr)[i].Title = i18n.TKey(language, (*arr)[i].Title)
			(*arr)[i].OperaLocation = i18n.TKey(language, (*arr)[i].OperaLocation)
		}
	}
	converI18n(language, &rows)

	// 导出文件名称
	dateStr := date.ParseDateToStr(end.UnixMilli(), date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("sys_log_operate_export_%d_%s.%s", len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_operate", fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	// 业务类型
	businessTypeFunc := func(v string) string {
		businessType := ""
		switch v {
		case "0":
			// 业务操作类型-其它
			businessType = i18n.TKey(language, "dictData.operType.other")
		case "1":
			// 业务操作类型-新增
			businessType = i18n.TKey(language, "dictData.operType.add")
		case "2":
			// 业务操作类型-修改
			businessType = i18n.TKey(language, "dictData.operType.edit")
		case "3":
			// 业务操作类型-删除
			businessType = i18n.TKey(language, "dictData.operType.delete")
		case "4":
			// 业务操作类型-授权
			businessType = i18n.TKey(language, "dictData.operType.auth")
		case "5":
			// 业务操作类型-导出
			businessType = i18n.TKey(language, "dictData.operType.export")
		case "6":
			// 业务操作类型-导入
			businessType = i18n.TKey(language, "dictData.operType.import")
		case "7":
			// 业务操作类型-强退
			businessType = i18n.TKey(language, "dictData.operType.forced quit")
		case "8":
			// 业务操作类型-清空数据
			businessType = i18n.TKey(language, "dictData.operType.clear")
		}
		return businessType
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				i18n.TKey(language, "log.operate.export.id"),
				i18n.TKey(language, "log.operate.export.title"),
				i18n.TKey(language, "log.operate.export.businessType"),
				i18n.TKey(language, "log.operate.export.operName"),
				i18n.TKey(language, "log.operate.export.method"),
				i18n.TKey(language, "log.operate.export.ip"),
				i18n.TKey(language, "log.operate.export.status"),
				i18n.TKey(language, "log.operate.export.operTime"),
				i18n.TKey(language, "log.operate.export.costTime"),
			},
		}
		for _, row := range rows {
			// 业务类型
			businessType := businessTypeFunc(row.BusinessType)

			// 状态
			statusValue := i18n.TKey(language, "dictData.fail")
			if row.StatusFlag == "1" {
				statusValue = i18n.TKey(language, "dictData.success")
			}
			data = append(data, []string{
				fmt.Sprint(row.ID),
				row.Title,
				businessType,
				row.OperaBy,
				row.OperaUrlMethod,
				row.OperaIp,
				statusValue,
				date.ParseDateToStr(row.OperaTime, date.YYYY_MM_DDTHH_MM_SSZ),
				fmt.Sprint(row.CostTime),
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": i18n.TKey(language, "log.operate.export.id"),
			"B1": i18n.TKey(language, "log.operate.export.title"),
			"C1": i18n.TKey(language, "log.operate.export.businessType"),
			"D1": i18n.TKey(language, "log.operate.export.operName"),
			"E1": i18n.TKey(language, "log.operate.export.method"),
			"F1": i18n.TKey(language, "log.operate.export.ip"),
			"G1": i18n.TKey(language, "log.operate.export.status"),
			"H1": i18n.TKey(language, "log.operate.export.operTime"),
			"I1": i18n.TKey(language, "log.operate.export.costTime"),
		}
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 业务类型
			businessType := businessTypeFunc(row.BusinessType)

			// 状态
			statusValue := i18n.TKey(language, "dictData.fail")
			if row.StatusFlag == "1" {
				statusValue = i18n.TKey(language, "dictData.success")
			}
			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: row.Title,
				"C" + idx: businessType,
				"D" + idx: row.OperaBy,
				"E" + idx: row.OperaUrlMethod,
				"F" + idx: row.OperaIp,
				"G" + idx: statusValue,
				"H" + idx: date.ParseDateToStr(row.OperaTime, date.YYYY_MM_DDTHH_MM_SSZ),
				"I" + idx: row.CostTime,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export operate log err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "log"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}

// exportLogin 导出系统登录日志数据
func (s BackupExportLogProcessor) exportLogin(hour int, fileType string) string {
	// 前 hour 小时
	now := time.Now()
	end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
	start := end.Add(-time.Duration(hour) * time.Hour)

	language := "en"
	query := map[string]string{
		"beginTime": fmt.Sprint(start.UnixMilli()),
		"endTime":   fmt.Sprint(end.UnixMilli()),
	}
	rows, total := s.sysLogLoginService.FindByPage(query, "")
	if total == 0 {
		return "no data"
	}

	// 闭包函数处理多语言
	converI18n := func(language string, arr *[]systemModel.SysLogLogin) {
		for i := range *arr {
			(*arr)[i].LoginLocation = i18n.TKey(language, (*arr)[i].LoginLocation)
			(*arr)[i].OS = i18n.TKey(language, (*arr)[i].OS)
			(*arr)[i].Browser = i18n.TKey(language, (*arr)[i].Browser)
			(*arr)[i].Msg = i18n.TKey(language, (*arr)[i].Msg)
		}
	}
	converI18n(language, &rows)

	// 导出文件名称
	dateStr := date.ParseDateToStr(end.UnixMilli(), date.YYYYMMDDHHMMSS)
	fileName := fmt.Sprintf("sys_log_login_export_%d_%s.%s", len(rows), dateStr, fileType)
	filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_login", fileName)
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}

	if fileType == "csv" {
		// 转换数据
		data := [][]string{
			{
				i18n.TKey(language, "log.login.export.id"),
				i18n.TKey(language, "log.login.export.userName"),
				i18n.TKey(language, "log.login.export.ip"),
				i18n.TKey(language, "log.login.export.location"),
				i18n.TKey(language, "log.login.export.os"),
				i18n.TKey(language, "log.login.export.browser"),
				i18n.TKey(language, "log.login.export.status"),
				i18n.TKey(language, "log.login.export.time"),
				i18n.TKey(language, "log.login.export.msg"),
			},
		}
		for _, row := range rows {
			// 状态
			statusValue := i18n.TKey(language, "dictData.fail")
			if row.StatusFlag == "1" {
				statusValue = i18n.TKey(language, "dictData.success")
			}
			data = append(data, []string{
				fmt.Sprint(row.ID),
				row.UserName,
				row.LoginIp,
				row.LoginLocation,
				row.OS,
				row.Browser,
				statusValue,
				date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ),
				row.Msg,
			})
		}
		// 输出到文件
		if err := file.WriterFileCSV(data, filePath); err != nil {
			logger.Errorf("export login log err => %v", err.Error())
			return "export err"
		}
	}

	if fileType == "xlsx" {
		// 第一行表头标题
		headerCells := map[string]string{
			"A1": i18n.TKey(language, "log.login.export.id"),
			"B1": i18n.TKey(language, "log.login.export.userName"),
			"C1": i18n.TKey(language, "log.login.export.ip"),
			"D1": i18n.TKey(language, "log.login.export.location"),
			"E1": i18n.TKey(language, "log.login.export.os"),
			"F1": i18n.TKey(language, "log.login.export.browser"),
			"G1": i18n.TKey(language, "log.login.export.status"),
			"H1": i18n.TKey(language, "log.login.export.time"),
			"I1": i18n.TKey(language, "log.login.export.msg"),
		}
		// 从第二行开始的数据
		dataCells := make([]map[string]any, 0)
		for i, row := range rows {
			idx := strconv.Itoa(i + 2)
			// 状态
			statusValue := i18n.TKey(language, "dictData.fail")
			if row.StatusFlag == "1" {
				statusValue = i18n.TKey(language, "dictData.success")
			}
			dataCells = append(dataCells, map[string]any{
				"A" + idx: row.ID,
				"B" + idx: row.UserName,
				"C" + idx: row.LoginIp,
				"D" + idx: row.LoginLocation,
				"E" + idx: row.OS,
				"F" + idx: row.Browser,
				"G" + idx: statusValue,
				"H" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ),
				"I" + idx: row.Msg,
			})
		}
		// 导出数据表格
		if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil {
			logger.Errorf("export login log err => %v", err.Error())
			return "export err"
		}
	}

	// 上传到FTP服务器
	if err := s.backupService.FTPPushFile(filePath, "log"); err != nil {
		return "ok, ftp err:" + err.Error()
	}
	return "ok"
}
