package cli

import (
	"fmt"
	"time"

	cid "github.com/ipfs/go-cid"
	"gopkg.in/urfave/cli.v2"

	"github.com/filecoin-project/lotus/api"
	"github.com/filecoin-project/lotus/build"
	"github.com/filecoin-project/lotus/chain"
)

var syncCmd = &cli.Command{
	Name:  "sync",
	Usage: "Inspect or interact with the chain syncer",
	Subcommands: []*cli.Command{
		syncStatusCmd,
		syncWaitCmd,
	},
}

var syncStatusCmd = &cli.Command{
	Name:  "status",
	Usage: "check sync status",
	Action: func(cctx *cli.Context) error {
		api, closer, err := GetFullNodeAPI(cctx)
		if err != nil {
			return err
		}
		defer closer()
		ctx := ReqContext(cctx)

		state, err := api.SyncState(ctx)
		if err != nil {
			return err
		}

		fmt.Println("sync status:")
		for i, ss := range state.ActiveSyncs {
			fmt.Printf("worker %d:\n", i)
			var base, target []cid.Cid
			var heightDiff int64
			if ss.Base != nil {
				base = ss.Base.Cids()
				heightDiff = int64(ss.Base.Height())
			}
			if ss.Target != nil {
				target = ss.Target.Cids()
				heightDiff = int64(ss.Target.Height()) - heightDiff
			} else {
				heightDiff = 0
			}
			fmt.Printf("\tBase:\t%s\n", base)
			fmt.Printf("\tTarget:\t%s\n", target)
			fmt.Printf("\tHeight diff:\t%d\n", heightDiff)
			fmt.Printf("\tStage: %s\n", chain.SyncStageString(ss.Stage))
			fmt.Printf("\tHeight: %d\n", ss.Height)
		}
		return nil
	},
}

var syncWaitCmd = &cli.Command{
	Name:  "wait",
	Usage: "Wait for sync to be complete",
	Action: func(cctx *cli.Context) error {
		napi, closer, err := GetFullNodeAPI(cctx)
		if err != nil {
			return err
		}
		defer closer()
		ctx := ReqContext(cctx)

		for {
			state, err := napi.SyncState(ctx)
			if err != nil {
				return err
			}

			head, err := napi.ChainHead(ctx)
			if err != nil {
				return err
			}

			working := 0
			for i, ss := range state.ActiveSyncs {
				switch ss.Stage {
				case api.StageSyncComplete:
				default:
					working = i
				case api.StageIdle:
					// not complete, not actively working
				}
			}

			ss := state.ActiveSyncs[working]

			var target []cid.Cid
			if ss.Target != nil {
				target = ss.Target.Cids()
			}

			fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)

			if time.Now().Unix()-int64(head.MinTimestamp()) < build.BlockDelay {
				fmt.Println("\nDone!")
				return nil
			}

			select {
			case <-ctx.Done():
				fmt.Println("\nExit by user")
				return nil
			case <-time.After(1 * time.Second):
			}
		}
	},
}