package pai_service

import (
	"os/exec"
	"io"
	"strings"
	"bufio"
	"chain33-pai/pkg/chain33"
	"github.com/33cn/chain33/types"
	log "github.com/33cn/chain33/common/log/log15"
	"net/http"
	"bytes"
	"io/ioutil"
	"encoding/json"
	"chain33-pai/pkg/setting"
)

var (
	pai_serial string
	 tlog = log.New("service", "pai_Service")
)

type Pai struct {
	Hardware string `json:"hardware"`
	Revision string	`json:"revision"`
	Serial   string `json:"serial"`
	//PeerList *types.PeerList
	LocalLastHeight int64 `json:"local_last_height"`
	LastHeight int64 `json:"last_height"`
	IsNtpSync  bool	`json:"is_ntp_sync"`
	WalletStatus *types.WalletStatus `json:"wallet_status"`
	NetInfo *types.NodeNetInfo `json:"net_info"`
	BtyVersion *types.VersionInfo `json:"bty_version"`
	Err string `json:"err"`
	Arch string `json:"arch"`
}

type ReqUpdatePai struct {
	Version string `json:"version" binding:"required"`
}

func (p *Pai) SetPai() error {
	p.Err = ""
	p.GetConfig()
	p.GetDevstatus()
	p.GetBtyVersion()
	p.SetPaiEnv()
	return nil
}

func (p *Pai) SetPaiEnv() error {
	var buf bytes.Buffer
	cmd := exec.Command("arch")
	cmd.Stdout = &buf
	cmd.Run()
	arch := buf.String()
	p.Arch = strings.Replace(arch,"\n","",-1)
	return nil
}

func (p *Pai) GetBtyVersion() error {
	client := &chain33.PaiClient{}
	v,err := client.Version()
	if err != nil {
		p.Err = err.Error()
		return err
	}
	p.BtyVersion = v
	return nil
}

func (p *Pai) GetConfig() bool {
	if pai_serial != "" {
		p.Serial = pai_serial
	}
	if p.Serial != "" {
		return true
	}
	config ,err := getPaiConfig("cat","/proc/cpuinfo")
	if err != nil {
		p.Err = err.Error()
		return false
	}
	if _,ok := config["serial"];ok {
		p.Serial = config["serial"]
		p.Hardware = config["hardware"]
		p.Revision = config["revision"]
		return true
	}
	return false
}

func (p *Pai) GetDevstatus() error {
	client := &chain33.PaiClient{}
	peerinfo,err := client.GetPeerInfo()
	if err != nil {
		tlog.Error("GetDevstatus peerinfo ","err",err)
		p.Err = err.Error()
		return err
	}

	for _,v := range peerinfo.Peers {
		if p.LastHeight < v.Header.Height {
			p.LastHeight = v.Header.Height
		}
		if v.Self {
			p.LocalLastHeight = v.Header.Height
		}
	}
	sync ,err := client.IsNtpClockSync()
	if err != nil {
		p.Err = err.Error()
		tlog.Error("GetDevstatus IsNtpClockSync"," err",err)
		return err
	}
	p.IsNtpSync = sync.IsOk
	netinfo,err := client.GetNetInfo()
	if err != nil {
		p.Err = err.Error()
		tlog.Error("GetDevstatus GetNetInfo"," err",err)
		return err
	}
	p.NetInfo = netinfo
	walletstatus,err := client.GetWalletStatus()
	if err != nil {
		p.Err = err.Error()
		tlog.Error("GetDevstatus GetWalletStatus ","err",err)
		return err
	}
	p.WalletStatus = walletstatus
	return nil
}

func getPaiConfig(command string ,arg ...string) (config map[string]string,err error) {
	//获取操作系统版本信息

	list := make(map[string]string, 0)
	cmd := exec.Command("cat", arg...)
	stdout, err := cmd.StdoutPipe()
	//tlog.Info(stdout)
	if err != nil {
		tlog.Info("getPaiConfig",err)
		return nil,err
	}
	defer stdout.Close()
	if err := cmd.Start(); err != nil {
		tlog.Info("getPaiConfig",err)
		return nil,err
	}
	rd := bufio.NewReader(stdout)
	for {
		line, err := rd.ReadString('\n')
		if err!=nil || io.EOF==err{
			break
		}else{
			//tlog.Info("line", line)
			l := strings.Split(line, ":")

			if len(l) == 2 {
				k := strings.ToLower(strings.TrimRight(strings.Trim(strings.Replace(l[0], "	", " ", -1), " "), " "))
				v := strings.Trim(strings.Replace(l[1], "\n", "", -1), " ")
				//tlog.Info("KEY:",k, "VAL:", v)
				if _, ok := list[k]; !ok {
					list[k] = v
					if k == "serial" {
						pai_serial = v
					}
				}
			}
		}
	}

	return list, nil
}

func (p *Pai) GetPaiLatestVersion(t int32) (string,error) {
	data := make(map[string]interface{})
	data["type"] = t
	bytesData, _ := json.Marshal(data)
	resp, err := http.Post(setting.Chain33Pai.VersionUrl,"application/json", bytes.NewReader(bytesData))
	if err != nil {
		return "",err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "",err
	}
	type res struct {
		Code int64
		Msg string
		Data string
	}
	var r res
	err = json.Unmarshal(body,&r)
	if err != nil {
		return "",err
	}
	return r.Data,nil
}