package gm_services

import (
	"context"
	"errors"
	"fmt"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/admin/ws"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/utility"
	"gadmin/utility/token"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"os"
	"os/exec"
	"strings"
	"time"
)

// ToolsRestart 重启服务
func ToolsRestart(ctx *gin.Context, params forms.ToolsRestartReq) (err error) {

	// 执行重启命令
	command := os.Getenv("BIN_PATH") + `/restart.sh ` + params.Version
	//logrus.Info(fmt.Sprintf("ToolsRestart run, command:%v", command))
	//
	//cmd := exec.Command("/bin/bash", "-c", command)
	//_, err = cmd.Output()
	//if err != nil {
	//	logrus.Warning(fmt.Sprintf("ToolsRestart err, command:%v err:%v", command, err))
	//	return
	//}

	// 重启记录
	createData := model.ToolsRestartLog{
		Version:   params.Version,
		AdminID:   token.GetUID(ctx),
		Username:  token.GetUserName(ctx),
		IP:        ctx.ClientIP(),
		UserAgent: ctx.Request.UserAgent(),
		Command:   command,
	}

	if err = query.Use(config.DB).ToolsRestartLog.WithContext(ctx).Create(&createData); err != nil {
		return
	}

	if createData.ID < 1 {
		return errors.New("创建重启记录失败，请稍后重试！")
	}

	if err := RunCommand(token.GetUID(ctx), createData, "/bin/bash", "-c", command); err != nil {
		logrus.Warning(fmt.Sprintf("ToolsRestart err, command:%v err:%v", command, err))
		return err
	}
	logrus.Println("OK..")
	return
}

func RunCommand(adminId int64, restartModel model.ToolsRestartLog, name string, arg ...string) error {
	var (
		cmd = exec.Command(name, arg...)
		std string
		q   = query.Use(config.DB).ToolsRestartLog
	)

	loadStdout(restartModel, "执行命令："+cmd.String()+"\r\n", &std)

	// 命令的错误输出和标准输出都连接到同一个管道
	stdout, err := cmd.StdoutPipe()
	cmd.Stderr = cmd.Stdout

	if err != nil {
		return err
	}
	if err = cmd.Start(); err != nil {
		return err
	}
	go func() {
		// 从管道中实时获取输出并打印到终端
		for {
			tmp := make([]byte, 1024)
			_, err := stdout.Read(tmp)
			if err != nil {
				if err.Error() != "EOF" {
					loadStdout(restartModel, "stdout.Read err:"+err.Error()+"\r\n", &std)
				}
				break
			}
			loadStdout(restartModel, string(tmp), &std)
		}

		if err = cmd.Wait(); err != nil {
			if err.Error() != "EOF" {
				loadStdout(restartModel, "cmd.Wait() err:"+err.Error()+"\r\n", &std)
			}
		}

		restartModel.Stdout = std
		restartModel.Latency = int64(time.Now().Sub(restartModel.CreatedAt).Seconds())
		_, err := q.WithContext(context.TODO()).Where(q.ID.Eq(restartModel.ID)).Updates(&restartModel)
		if err != nil {
			logrus.Println("restartModel Updates err：", err)
		}
		loadStdout(restartModel, "restart complete", &std)
	}()
	return nil
}

// loadStdout 装载重启日志消息
func loadStdout(restartModel model.ToolsRestartLog, msg string, std *string) {
	msg = utility.Rmu0000(msg)
	msg = strings.ReplaceAll(msg, "\\n\\t", "\r\n")
	logrus.Info("loadStdout：", msg)
	*std = *std + msg
	if restartModel.AdminID > 0 {
		msgData := ws.Msg{
			Id:   restartModel.ID,
			Type: consts.SocketRestartLog,
			Code: consts.CodeSuccess,
			Msg:  msg,
		}
		go ws.SendToAdmin(restartModel.AdminID, msgData)
	}
}

func ToolsRestartView(ctx *gin.Context, params forms.ToolsRestartViewReq) (models *model.ToolsRestartLog, err error) {
	q := query.Use(config.DB).ToolsRestartLog
	models, err = q.WithContext(ctx).Where(q.ID.Eq(params.ID)).Last()
	if err != nil {
		return nil, err
	}

	return
}

// ToolsRestartLogList 重启记录
func ToolsRestartLogList(ctx *gin.Context, params forms.ToolsRestartLogReq) (models forms.ToolsRestartLogRes, err error) {

	q := query.Use(config.DB).ToolsRestartLog
	m := q.WithContext(ctx)

	// 设置分页
	if params.Limit <= 0 {
		params.Limit = 10
	}

	if params.Page <= 0 {
		params.Page = 1
	}
	offset := (params.Page - 1) * params.Limit

	lists, err := m.Select(q.ID, q.AdminID, q.CreatedAt, q.Username, q.Version, q.IP, q.Command, q.Latency).
		Order(q.ID.Desc()).Limit(params.Limit).Offset(offset).Find()
	if err != nil {
		return models, err
	}
	count, err := m.Count()
	if err != nil {
		return models, err
	}

	models.List = lists
	models.Limit = params.Limit
	models.Page = params.Page
	models.TotalCount = count

	return
}
