package plugin_mp4

import (
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/shirou/gopsutil/v4/disk"
	"gorm.io/gorm"
	"m7s.live/v5"
	"m7s.live/v5/pkg/task"
)

// mysql数据库里Exception 定义异常结构体
type Exception struct {
	CreateTime string `json:"createTime" gorm:"type:varchar(50)"`
	AlarmType  string `json:"alarmType" gorm:"type:varchar(50)"`
	AlarmDesc  string `json:"alarmDesc" gorm:"type:varchar(50)"`
	ServerIP   string `json:"serverIP" gorm:"type:varchar(50)"`
	StreamPath string `json:"streamPath" gorm:"type:varchar(50)"`
}

// // 向第三方发送异常报警
// func (p *MP4Plugin) SendToThirdPartyAPI(exception *Exception) {
// 	exception.CreateTime = time.Now().Format("2006-01-02 15:04:05")
// 	exception.ServerIP = p.GetCommonConf().PublicIP
// 	data, err := json.Marshal(exception)
// 	if err != nil {
// 		p.Error("SendToThirdPartyAPI", " marshalling exception error", err.Error())
// 		return
// 	}
// 	err = p.DB.Create(&exception).Error
// 	if err != nil {
// 		p.Error("SendToThirdPartyAPI", "insert into db error", err.Error())
// 		return
// 	}
// 	resp, err := http.Post(p.ExceptionPostUrl, "application/json", bytes.NewBuffer(data))
// 	if err != nil {
// 		p.Error("SendToThirdPartyAPI", "Error sending exception to third party API error", err.Error())
// 		return
// 	}
// 	defer resp.Body.Close()

// 	if resp.StatusCode != http.StatusOK {
// 		p.Error("SendToThirdPartyAPI", "Failed to send exception, status code:", resp.StatusCode)
// 	} else {
// 		p.Info("SendToThirdPartyAPI", "Exception sent successfully!")
// 	}
// }

// // 磁盘超上限报警
// func (p *DeleteRecordTask) getDisckException(streamPath string) bool {
// 	if p.getDiskOutOfSpace(p.DiskMaxPercent) {
// 		exceptionChannel <- &Exception{AlarmType: "disk alarm", AlarmDesc: "disk is full", StreamPath: streamPath}
// 		return true
// 	}
// 	return false
// }

// 判断磁盘使用量是否中超限
func (p *DeleteRecordTask) getDiskOutOfSpace(filePath string) bool {
	exePath := filepath.Dir(filePath)
	d, err := disk.Usage(exePath)
	if err != nil || d == nil {
		p.Error("getDiskOutOfSpace", "error", err)
		return false
	}
	p.plugin.Debug("getDiskOutOfSpace", "current path", exePath, "disk UsedPercent", d.UsedPercent, "total disk space", d.Total,
		"disk free", d.Free, "disk usage", d.Used, "AutoOverWriteDiskPercent", p.AutoOverWriteDiskPercent, "DiskMaxPercent", p.DiskMaxPercent)
	return d.UsedPercent >= p.AutoOverWriteDiskPercent
}

func (p *DeleteRecordTask) deleteOldestFile() {
	//当当前磁盘使用量大于AutoOverWriteDiskPercent自动覆盖磁盘使用量配置时，自动删除最旧的文件
	//连续录像删除最旧的文件
	// 创建一个数组来存储所有的conf.FilePath
	var filePaths []string
	if len(p.plugin.GetCommonConf().OnPub.Record) > 0 {
		for _, conf := range p.plugin.GetCommonConf().OnPub.Record {
			// 处理路径，去掉最后的/$0部分，只保留目录部分
			dirPath := filepath.Dir(conf.FilePath)
			p.Info("deleteOldestFile", "original filepath", conf.FilePath, "processed filepath", dirPath)
			filePaths = append(filePaths, dirPath)
		}
	}
	if p.plugin.EventRecordFilePath != "" {
		// 同样处理EventRecordFilePath
		dirPath := filepath.Dir(p.plugin.EventRecordFilePath)
		filePaths = append(filePaths, dirPath)
	}
	for _, filePath := range filePaths {
		for p.getDiskOutOfSpace(filePath) {
			queryRecord := m7s.RecordStream{
				EventLevel: m7s.EventLevelLow, // 查询条件：event_level = 1,非重要事件
			}
			var eventRecords []m7s.RecordStream
			// 使用不同的方法进行路径匹配，避免ESCAPE语法问题
			// 解决方案：用MySQL能理解的简单方式匹配路径前缀
			basePath := filePath
			// 直接替换所有反斜杠，不需要判断是否包含
			basePath = strings.Replace(basePath, "\\", "\\\\", -1)
			searchPattern := basePath + "%"
			p.Info("deleteOldestFile", "searching with path pattern", searchPattern)

			err := p.DB.Where(&queryRecord).Where("end_time IS NOT NULL").
				Where("file_path LIKE ?", searchPattern).
				Order("end_time ASC").Limit(1).Find(&eventRecords).Error
			if err == nil {
				if len(eventRecords) > 0 {
					for _, record := range eventRecords {
						p.Info("deleteOldestFile", "ready to delete oldestfile,ID", record.ID, "create time", record.EndTime, "filepath", record.FilePath)
						err = os.Remove(record.FilePath)
						if err != nil {
							p.Error("deleteOldestFile", "delete file from disk error", err)
						} else {
							err = p.DB.Delete(&record).Error
							if err != nil {
								p.Error("deleteOldestFile", "delete record from disk error", err)
							}
						}
					}
				}
			} else {
				p.Error("deleteOldestFile", "search record from db error", err)
			}
			time.Sleep(time.Second * 3)
		}
	}
}

type DeleteRecordTask struct {
	task.TickTask
	DiskMaxPercent           float64
	AutoOverWriteDiskPercent float64
	RecordFileExpireDays     int
	DB                       *gorm.DB
	plugin                   *MP4Plugin
}

func (t *DeleteRecordTask) GetTickInterval() time.Duration {
	return 1 * time.Minute
}

func (t *DeleteRecordTask) Tick(any) {
	t.deleteOldestFile()
	if t.RecordFileExpireDays <= 0 {
		return
	}
	//搜索event_records表中event_level值为1的（非重要）数据，并将其create_time与当前时间比对，大于RecordFileExpireDays则进行删除，数据库标记is_delete为1，磁盘上删除录像文件
	var eventRecords []m7s.RecordStream
	expireTime := time.Now().AddDate(0, 0, -t.RecordFileExpireDays)
	t.Debug("RecordFileExpireDays is set to auto delete oldestfile", "expireTime", expireTime.Format("2006-01-02 15:04:05"))
	queryRecord := m7s.RecordStream{
		EventLevel: m7s.EventLevelLow, // 查询条件：event_level = low,非重要事件
	}
	err := t.DB.Where(&queryRecord).Find(&eventRecords, "end_time < ? AND end_time IS NOT NULL", expireTime).Error
	if err == nil {
		for _, record := range eventRecords {
			t.Info("RecordFileExpireDays is set to auto delete oldestfile", "ID", record.ID, "create time", record.EndTime, "filepath", record.FilePath)
			err = os.Remove(record.FilePath)
			if err != nil {
				t.Error("RecordFileExpireDays set to auto delete oldestfile", "delete file from disk error", err)
			}
			err = t.DB.Delete(&record).Error
			if err != nil {
				t.Error("RecordFileExpireDays set to auto delete oldestfile", "delete record from db error", err)
			}
		}
	}
}
