// stm: #unit
package main

import (
	"testing"

	"github.com/ipfs/go-cid"
	mh "github.com/multiformats/go-multihash"
	"github.com/stretchr/testify/assert"
)

func TestAppendCIDsToWindow(t *testing.T) {
	//stm: @CMD_HEALTH_APPEND_CIDS_001
	assert := assert.New(t)
	var window CidWindow
	threshold := 3
	cid0 := makeCID("0")
	cid1 := makeCID("1")
	cid2 := makeCID("2")
	cid3 := makeCID("3")
	window = appendCIDsToWindow(window, []cid.Cid{cid0}, threshold)
	window = appendCIDsToWindow(window, []cid.Cid{cid1}, threshold)
	window = appendCIDsToWindow(window, []cid.Cid{cid2}, threshold)
	window = appendCIDsToWindow(window, []cid.Cid{cid3}, threshold)
	assert.Len(window, 3)
	assert.Equal(window[0][0], cid1)
	assert.Equal(window[1][0], cid2)
	assert.Equal(window[2][0], cid3)
}

func TestCheckWindow(t *testing.T) {
	//stm: @CMD_HEALTH_APPEND_CIDS_001, @CMD_HEALTH_CHECK_WINDOW_001
	assert := assert.New(t)
	threshold := 3

	var healthyHeadCheckWindow CidWindow
	healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	ok := checkWindow(healthyHeadCheckWindow, threshold)
	assert.True(ok)

	var healthyHeadCheckWindow1 CidWindow
	healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
		makeCID("abcd"),
	}, threshold)
	healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	ok = checkWindow(healthyHeadCheckWindow1, threshold)
	assert.True(ok)

	var healthyHeadCheckWindow2 CidWindow
	healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	ok = checkWindow(healthyHeadCheckWindow2, threshold)
	assert.True(ok)

	var healthyHeadCheckWindow3 CidWindow
	healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	ok = checkWindow(healthyHeadCheckWindow3, threshold)
	assert.True(ok)

	var healthyHeadCheckWindow4 CidWindow
	healthyHeadCheckWindow4 = appendCIDsToWindow(healthyHeadCheckWindow4, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, threshold)
	ok = checkWindow(healthyHeadCheckWindow4, threshold)
	assert.True(ok)

	var healthyHeadCheckWindow5 CidWindow
	healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
		makeCID("bbff"),
	}, 5)
	healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
		makeCID("bbcd"),
		makeCID("bbfe"),
	}, 5)
	healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
		makeCID("abcd"),
	}, 5)
	healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
		makeCID("cbcd"),
		makeCID("cbfe"),
	}, 5)
	healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
		makeCID("cbcd"),
		makeCID("cbfe"),
	}, 5)
	ok = checkWindow(healthyHeadCheckWindow5, threshold)
	assert.True(ok)

	var unhealthyHeadCheckWindow CidWindow
	unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
		makeCID("abcd"),
		makeCID("fbcd"),
	}, threshold)
	unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
		makeCID("abcd"),
		makeCID("fbcd"),
	}, threshold)
	unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
		makeCID("abcd"),
		makeCID("fbcd"),
	}, threshold)
	ok = checkWindow(unhealthyHeadCheckWindow, threshold)
	assert.False(ok)

	var unhealthyHeadCheckWindow1 CidWindow
	unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{
		makeCID("abcd"),
		makeCID("fbcd"),
	}, threshold)
	unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{
		makeCID("abcd"),
		makeCID("fbcd"),
	}, threshold)
	ok = checkWindow(unhealthyHeadCheckWindow1, threshold)
	assert.True(ok)

	var unhealthyHeadCheckWindow2 CidWindow
	unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
		makeCID("abcd"),
	}, threshold)
	ok = checkWindow(unhealthyHeadCheckWindow2, threshold)
	assert.False(ok)
}

func makeCID(s string) cid.Cid {
	h1, err := mh.Sum([]byte(s), mh.SHA2_256, -1)
	if err != nil {
		log.Fatal(err)
	}
	return cid.NewCidV1(0x55, h1)
}
