package app

import (
	"time"
	"chain33-pai/pkg/setting"
	"bytes"
	"os/exec"
	"fmt"
	"chain33-pai/service/pai_service"
	"errors"
	"os"
)

var (
	btyPath string
)

func RaspberryChan() {
	for {
		if value,ok := <- JobChan; ok {
			tlog.Info("raspberrychan","msg",value)
			if value.Name == "" {
				continue
			}
			path := GetAbsPath(setting.BityuanSetting.Name)
			if path != "" {
				btyPath = path
			}
			switch value.Name {
			case "ROLLBACK":
				err := rollback()
				if err == nil {
					tlog.Info("rollback success","err",nil)
				} else {
					tlog.Error("rollback fail ","err",err)
				}
			case "BACKUP":
				err := backup()
				if err == nil {
					tlog.Info("backup success","err",nil)
				} else {
					tlog.Error("backup fail ","err",err)
				}
			case "RECOVER":
				err := recoverNode()
				if err == nil {
					tlog.Info("recover success","err",nil)
				} else {
					tlog.Error("recover fail ","err",err)
				}
			case "DELETEBACKUP":
				err := deleteBackup()
				if err == nil {
					tlog.Info("deleteBackup success","err",nil)
				} else {
					tlog.Error("deleteBackup fail ","err",err)
				}
			}

		}
		time.Sleep(time.Second * 1)
	}
}


func rollback() error {
	BityuanFlag.Lock.Lock()
	defer BityuanFlag.Lock.Unlock()
	BityuanFlag.Flag = true
	_,err := SafeCloseNode()
	if err != nil {
		BityuanFlag.Flag  = false
		return err
	}
	var pai pai_service.Pai
	err = pai.SetPai()
	if err != nil {
		tlog.Error("SetPai","err",err)
		BityuanFlag.Flag  = false
		return err
	}
	if pai.LocalLastHeight == 0 {
		tlog.Error("LocalLastHeight","height",pai.LocalLastHeight)
		BityuanFlag.Flag  = false
		return err
	}
	rollheight := pai.LocalLastHeight - 1000
	if (pai.LocalLastHeight - 1000) <= 0 {
		rollheight = 1
	}
	isrun := MakeSureBtyIsNotRun()
	if isrun {
		BityuanFlag.Flag  = false
		return errors.New("bty is running")
	}
	tlog.Info("rollback start","height",pai.LocalLastHeight,"rollbackheight",rollheight)
	var buf bytes.Buffer
	if btyPath == "" {
		tlog.Error("GetAbsPath","err","btyPath not exists")
		BityuanFlag.Flag  = false
		return err
	}
	cmd := exec.Command(btyPath+"/"+setting.BityuanSetting.Name, "-rollback",fmt.Sprintf("%d",rollheight))
	cmd.Stdout = &buf
	err = cmd.Run()
	if err != nil {
		BityuanFlag.Flag  = false
		return err
	}
	tlog.Info("rollback end","height",pai.LocalLastHeight,"rollbackheight",rollheight)
	BityuanFlag.Flag  = false
	return nil
}

func backup() error {
	BityuanFlag.Lock.Lock()
	defer BityuanFlag.Lock.Unlock()
	if BityuanFlag.Flag {
		return errors.New("env err")
	}
	BityuanFlag.Flag = true
	ok,err := SafeCloseNode()
	if err != nil  {
		BityuanFlag.Flag = false
		tlog.Error("SafeCloseNode","err",err)
		return err
	}
	if !ok {
		BityuanFlag.Flag = false
		return errors.New("env err")
	}
	isrun := MakeSureBtyIsNotRun()
	if isrun {
		BityuanFlag.Flag  = false
		return errors.New("bty is running")
	}
	return SafeBackup()
}

func SafeBackup() error {
	var buf bytes.Buffer
	backup := exec.Command("cp","-r",btyPath+"/datadir",btyPath+"/datadir_backup")
	backup.Stderr = &buf
	if err := backup.Run();err != nil {
		tlog.Error("SafeBackup","err",buf.String())
		return err
	}
	return nil
}

func recoverNode() error {
	BityuanFlag.Lock.Lock()
	defer BityuanFlag.Lock.Unlock()
	if btyPath == "" {
		tlog.Error("btyPath empty","err","node not exists")
		return errors.New("node not exists")
	}
	backupPath := btyPath + "/datadir_backup"
	if _,err := os.Stat(backupPath);err != nil {
		if os.IsNotExist(err) {
			tlog.Error("backup file not exists","err",backupPath)
			return errors.New("backup file not exists")
		}
	}
	remove := exec.Command("rm","-rf",btyPath+"/datadir")
	err := remove.Run()
	if err != nil {
		tlog.Error("rm -rf datadir","err",err)
		return err
	}

	recover := exec.Command("cp","-r",backupPath,btyPath+"/datadir")
	err = recover.Run()
	if err != nil {
		tlog.Error("cp -r datadir_backup datadir","err",err)
		return err
	}
	return nil
}

func deleteBackup() error {
	btyPath := GetAbsPath(setting.BityuanSetting.Name)
	if btyPath == "" {
		tlog.Error("btyPath empty","err","node not exists")
		return errors.New("node not exists")
	}
	backupPath := btyPath + "/datadir_backup"
	if _,err := os.Stat(backupPath);err != nil {
		if os.IsNotExist(err) {
			tlog.Error("backup file not exists","err",backupPath)
			return errors.New("backup file not exists")
		}
	}
	remove := exec.Command("rm","-rf","datadir_backup")
	err := remove.Run()
	if err != nil {
		tlog.Error("rm -rf datadir_backup","err",err)
		return err
	}
	return nil
}

func MakeSureBtyIsNotRun() bool {
	s := time.Now()
	defer func() {
		tlog.Info("MakeSureBtyIsNotRun","cost",time.Since(s))
	}()
	for {
		info := getProcessInfo(setting.BityuanSetting.Name)
		if info == "" {
			return false
		}
	}
	return true
}