package log

import (
	"errors"
	"fmt"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"log-server/global"
	"log-server/model/log"
	"log-server/model/log/request"
	"log-server/model/log/response"
	loging2 "log-server/service/log/loging"
	"os"
	"time"
)

type ServiceComputer struct {
	Logical loging2.LogicalLog
}

func (exa *ServiceComputer) ParseExcel2InfoList(filePath string) (err error) {
	skipHeader := true
	fixedHeader := []string{"pc_code", "user", "supplier"}
	file, err := excelize.OpenFile(filePath)
	if err != nil {
		return err
	}
	var Computers []*log.Computer
	rows, err := file.Rows("Sheet1")
	if err != nil {
		return err
	}
	for rows.Next() {
		row, err := rows.Columns()
		if err != nil {
			return err
		}
		if skipHeader {
			if exa.compareStrSlice(row, fixedHeader) {
				skipHeader = false
				continue
			} else {
				return errors.New("Excel格式错误")
			}
		}
		if len(row) != len(fixedHeader) {
			continue
		}
		c := new(log.Computer)
		c.PcCode = row[0]
		c.User = row[1]
		c.Supplier = row[2]
		c.CreateTime = time.Now().Format("2006-01-02 15:04:05")
		c.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
		c.Status = 1
		Computers = append(Computers, c)
	}
	err = os.RemoveAll(filePath)
	if err != nil {
		return
	}
	err = global.GVA_DB.Create(Computers).Error
	if err != nil {
		return
	}
	var cp log.Computer
	err = cp.DelAllOnlinePcCodeCache()
	return
}

func (exa *ServiceComputer) compareStrSlice(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	if (b == nil) != (a == nil) {
		return false
	}
	for key, value := range a {
		if value != b[key] {
			return false
		}
	}
	return true
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetPcInfoList
//@description: 分页获取数据,
//@param: card card.Card, info request.PageInfo, order string, desc bool
//@return: list interface{}, total int64, err error
func (apiService *ServiceComputer) GetPcInfoList(api log.Computer, info request.PageInfo, order string, desc bool) (list interface{}, total int64, err error) {
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	db := global.GVA_DB.Model(&log.Computer{})
	var apiList []log.Computer

	if api.PcCode != "" {
		db = db.Where("pc_code LIKE ?", "%"+api.PcCode+"%")
	}

	if api.User != "" {
		db = db.Where("user LIKE ?", "%"+api.User+"%")
	}

	if api.Status != 0 {
		if api.Status == -1 {
			db = db.Where("status = ?", 0)
		}
	}

	err = db.Count(&total).Error

	if err != nil {
		return apiList, total, err
	} else {
		db = db.Limit(limit).Offset(offset)
		if order != "" {
			var OrderStr string
			// 设置有效排序key 防止sql注入
			// 感谢 Tom4t0 提交漏洞信息
			orderMap := make(map[string]bool, 4)
			orderMap["id"] = true
			orderMap["pc_code"] = true
			orderMap["user"] = true
			if orderMap[order] {
				if desc {
					OrderStr = order + " desc"
				} else {
					OrderStr = order
				}
			} else { // didn't matched any order key in `orderMap`
				err = fmt.Errorf("非法的排序字段: %v", order)
				return apiList, total, err
			}

			err = db.Order(OrderStr).Find(&apiList).Error
		} else {
			err = db.Order("id").Find(&apiList).Error
		}
	}
	var apisReply []*response.GetPcListReply
	if len(apiList) != 0 {
		for _, apiInfo := range apiList {
			apiReply := new(response.GetPcListReply)
			apiReply.Id = apiInfo.Id
			apiReply.Status = apiInfo.Status
			apiReply.PcCode = apiInfo.PcCode
			apiReply.Supplier = apiInfo.Supplier
			apiReply.UpdateTime = apiInfo.UpdateTime
			apiReply.CreateTime = apiInfo.CreateTime
			apiReply.User = apiInfo.User
			apisReply = append(apisReply, apiReply)
		}

	}
	return apisReply, total, err
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetPcById
//@description: 根据id获取pc
//@param: id uint
//@return: apiReply response.GetPcListReply, err error
func (c *ServiceComputer) GetPcById(id int) (cardReply response.GetPcListReply, err error) {
	var api log.Computer
	err = global.GVA_DB.Where("id = ?", id).First(&api).Error
	if err != nil {
		return
	}
	cardReply.Id = api.Id
	cardReply.Status = api.Status
	cardReply.Supplier = api.Supplier
	cardReply.User = api.User
	cardReply.PcCode = api.PcCode
	cardReply.CreateTime = api.CreateTime
	cardReply.UpdateTime = api.UpdateTime
	return
}

func (a *ServiceComputer) CreatePc(c log.Computer) (err error) {
	if !errors.Is(global.GVA_DB.Where("pc_code = ?", c.PcCode).First(&log.Computer{}).Error, gorm.ErrRecordNotFound) {
		return errors.New("存在相同编号")
	}
	c.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	c.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	err = global.GVA_DB.Create(&c).Error
	if err != nil {
		return err
	}
	if c.Status == 1 {
		err = c.UpdateOnlinePcCodeCache(c.PcCode, c.User)
	}
	return
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdatePc
//@description: 根据id更新pc
//@param: Computer log.Computer
//@return: err error
func (a *ServiceComputer) UpdatePc(c log.Computer) (err error) {
	var oldA log.Computer
	err = global.GVA_DB.Where("id = ?", c.Id).First(&oldA).Error
	if err != nil {
		return err
	}
	if oldA.PcCode != c.PcCode {
		if !errors.Is(global.GVA_DB.Where("pc_code = ?", c.PcCode).First(&log.Computer{}).Error, gorm.ErrRecordNotFound) {
			return errors.New("存在相同编号")
		}
	}
	var updateInfo = make(map[string]interface{})
	updateInfo["pc_code"] = c.PcCode
	updateInfo["user"] = c.User
	updateInfo["supplier"] = c.Supplier
	updateInfo["status"] = c.Status
	err = global.GVA_DB.Table("computer").Where("id", c.Id).Updates(updateInfo).Error
	if err != nil {
		return err
	}
	if c.Status == -1 {
		err = oldA.DelOnlinePcCodeCache(c.PcCode)
	} else if c.Status == 1 {
		err = oldA.DelOnlinePcCodeCache(oldA.PcCode)
		err = oldA.UpdateOnlinePcCodeCache(c.PcCode, c.User)
	}
	return err
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdatePcStatus
//@description: 根据id更新 status
//@param: Computer log.Computer
//@return: err error
func (a *ServiceComputer) UpdatePcStatus(c log.Computer) (err error) {
	var oldA log.Computer
	err = global.GVA_DB.Where("id = ?", c.Id).First(&oldA).Error
	if err != nil {
		return err
	}
	err = global.GVA_DB.Table("computer").Where("id", c.Id).Update("status", c.Status).Error
	return err
}
