// stm: #unit
package store

import (
	"testing"
	"time"

	"github.com/filecoin-project/lotus/chain/types"
	"github.com/filecoin-project/lotus/chain/types/mock"
)

func TestHeadChangeCoalescer(t *testing.T) {
	//stm: @CHAIN_STORE_COALESCE_HEAD_CHANGE_001
	notif := make(chan headChange, 1)
	c := NewHeadChangeCoalescer(func(revert, apply []*types.TipSet) error {
		notif <- headChange{apply: apply, revert: revert}
		return nil
	},
		100*time.Millisecond,
		200*time.Millisecond,
		10*time.Millisecond,
	)
	defer c.Close() //nolint

	b0 := mock.MkBlock(nil, 0, 0)
	root := mock.TipSet(b0)
	bA := mock.MkBlock(root, 1, 1)
	tA := mock.TipSet(bA)
	bB := mock.MkBlock(root, 1, 2)
	tB := mock.TipSet(bB)
	tAB := mock.TipSet(bA, bB)
	bC := mock.MkBlock(root, 1, 3)
	tABC := mock.TipSet(bA, bB, bC)
	bD := mock.MkBlock(root, 1, 4)
	tABCD := mock.TipSet(bA, bB, bC, bD)
	bE := mock.MkBlock(root, 1, 5)
	tABCDE := mock.TipSet(bA, bB, bC, bD, bE)

	c.HeadChange(nil, []*types.TipSet{tA})                      //nolint
	c.HeadChange(nil, []*types.TipSet{tB})                      //nolint
	c.HeadChange([]*types.TipSet{tA, tB}, []*types.TipSet{tAB}) //nolint
	c.HeadChange([]*types.TipSet{tAB}, []*types.TipSet{tABC})   //nolint

	change := <-notif

	if len(change.revert) != 0 {
		t.Fatalf("expected empty revert set but got %d elements", len(change.revert))
	}
	if len(change.apply) != 1 {
		t.Fatalf("expected single element apply set but got %d elements", len(change.apply))
	}
	if change.apply[0] != tABC {
		t.Fatalf("expected to apply tABC")
	}

	c.HeadChange([]*types.TipSet{tABC}, []*types.TipSet{tABCD})   //nolint
	c.HeadChange([]*types.TipSet{tABCD}, []*types.TipSet{tABCDE}) //nolint

	change = <-notif

	if len(change.revert) != 1 {
		t.Fatalf("expected single element revert set but got %d elements", len(change.revert))
	}
	if change.revert[0] != tABC {
		t.Fatalf("expected to revert tABC")
	}
	if len(change.apply) != 1 {
		t.Fatalf("expected single element apply set but got %d elements", len(change.apply))
	}
	if change.apply[0] != tABCDE {
		t.Fatalf("expected to revert tABC")
	}

}
