package pai_service

import (
	"os/exec"
	"fmt"
	"io"
	"strings"
	"bufio"
	"chain33-pai/pkg/chain33"
	"chain33-pai/pkg/logging"
	"github.com/33cn/chain33/types"
	"chain33-pai/models"
	"time"
)

var (
	pai_serial string
)

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"`
}

type MinedInfo struct {
	MinedAmount int64 `json:"mined_amount"`
	MinedTicketCount int64 `json:"mined_ticket_count"`
	MiningTicketCount int64 `json:"mining_ticket_count"`
	MinerStartTime int64 `json:"miner_start_time"`
	MinerEndTime int64 `json:"miner_end_time"`
	ServeTime int64 `json:"serve_time"`
	MinedList []*MinedTxInfo `json:"mined_list"`
	MinedTotal int64 `json:"mined_total"`
}

type MinedTxInfo struct {
	Height int64 `json:"height"`
	Hash string `json:"hash"`
	Amount int64 `json:"amount"`
	BlockTime int64 `json:"block_time"`
}


type ReqMineTime struct {
	Addr string `json:"addr" binding:"required"`
	Flag string `json:"flag"`
}

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 {
		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 {
		logging.Error("GetDevstatus peerinfo err",err)
		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 {
		logging.Error("GetDevstatus IsNtpClockSync err",err)
		return err
	}
	p.IsNtpSync = sync.IsOk
	netinfo,err := client.GetNetInfo()
	if err != nil {
		logging.Error("GetDevstatus GetNetInfo err",err)
		return err
	}
	p.NetInfo = netinfo
	walletstatus,err := client.GetWalletStatus()
	if err != nil {
		logging.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()
	//fmt.Println(stdout)
	if err != nil {
		fmt.Println(err)
		return nil,err
	}
	defer stdout.Close()
	if err := cmd.Start(); err != nil {
		fmt.Println(err)
		return nil,err
	}
	rd := bufio.NewReader(stdout)
	for {
		line, err := rd.ReadString('\n')
		if err!=nil || io.EOF==err{
			break
		}else{
			//fmt.Println("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), " ")
				//fmt.Println("KEY:",k, "VAL:", v)
				if _, ok := list[k]; !ok {
					list[k] = v
					if k == "serial" {
						pai_serial = v
					}
				}
			}
		}
	}

	return list, nil
}

func (p *Pai) GetTicketInfo(req *models.ReqTicketInfo) (*MinedInfo,error) {
	var info MinedInfo
	txsList := make([]*MinedTxInfo,0)
	stat,err := models.GetAddr(req.Addr)
	if err != nil {
		logging.Error("models.GetAddr err",err)
		return nil,err
	}
	if req.Detail {
		count,err := models.GetMinerTxsTotal(req.Addr)
		if err != nil {
			logging.Error("models.GetMinerTxsCount err",err)
		}
		txs,err := models.GetMinerTxs(req)
		if err != nil {
			logging.Error("models.GetAddrs err",err)
			return nil,err
		}
		for _, v := range txs {
			var t MinedTxInfo
			t.Height = v.Height
			t.Amount = v.Amount
			t.BlockTime = v.Time
			t.Hash = v.Hash
			txsList = append(txsList,&t)
		}
		info.MinedTotal = count
	}
	info.MinedAmount = stat.MinedAmount
	info.MinedTicketCount = stat.MinedTicketCount
	info.MiningTicketCount = stat.MiningTicketCount
	info.MinerStartTime = stat.MinerStartTime
	info.MinerEndTime = stat.MinerEndTime
	info.ServeTime = time.Now().Unix()
	info.MinedList = txsList

	return &info,nil
}