package test

import (
	"fmt"

	dbm "github.com/vapor/database/leveldb"
	"github.com/vapor/protocol"
	"github.com/vapor/protocol/bc/types"
)

func declChain(name string, baseChain *protocol.Chain, baseHeight uint64, height uint64) (*protocol.Chain, error) {
	chainDB := dbm.NewDB(name, "leveldb", name)
	chain, _, _, err := MockChain(chainDB)
	if err != nil {
		return nil, err
	}

	if baseChain == nil {
		if err := AppendBlocks(chain, height); err != nil {
			return nil, err
		}
		return chain, nil
	}

	for i := uint64(1); i <= baseHeight; i++ {
		block, err := baseChain.GetBlockByHeight(i)
		if err != nil {
			return nil, err
		}
		if _, err := chain.ProcessBlock(block); err != nil {
			return nil, err
		}
	}

	err = AppendBlocks(chain, height-baseHeight)
	return chain, err
}

func ancestorOf(c1 *protocol.Chain, c2 *protocol.Chain) (*types.Block, error) {
	start := c1.BestBlockHeight()
	if c2.BestBlockHeight() < c1.BestBlockHeight() {
		start = c2.BestBlockHeight()
	}

	for i := start; i >= 0; i-- {
		b1, err := c1.GetBlockByHeight(i)
		if err != nil {
			return nil, err
		}
		b2, err := c2.GetBlockByHeight(i)
		if err != nil {
			return nil, err
		}
		if b1.Hash() == b2.Hash() {
			return b1, nil
		}
	}
	return nil, fmt.Errorf("can't find ancestor")
}

func merge(c1 *protocol.Chain, c2 *protocol.Chain) error {
	// c1 and c2 are same
	if c1.BestBlockHeight() == c2.BestBlockHeight() && *c1.BestBlockHash() == *c2.BestBlockHash() {
		return nil
	}

	ancestor, err := ancestorOf(c1, c2)
	if err != nil {
		return err
	}

	processBlocks := func(dest *protocol.Chain, src *protocol.Chain, height uint64) error {
		for h := src.BestBlockHeight(); h > height; h-- {
			block, err := src.GetBlockByHeight(h)
			if err != nil {
				return err
			}
			_, err = dest.ProcessBlock(block)
			if err != nil {
				return err
			}
		}
		return nil
	}

	if err := processBlocks(c1, c2, ancestor.Height); err != nil {
		return err
	}
	return processBlocks(c2, c1, ancestor.Height)
}
