package cmd

import (
	"fmt"

	"0chain.net/core/config"
	"0chain.net/smartcontract/benchmark/main/cmd/log"

	"0chain.net/smartcontract/multisigsc"

	cviper "0chain.net/core/viper"
	bk "0chain.net/smartcontract/benchmark"
	"github.com/spf13/viper"
)

func GetViper(loadPath string) {
	viper.SetConfigType("yaml")
	viper.SetConfigName("benchmark")
	viper.AddConfigPath(loadPath)
	viper.AddConfigPath("../config/")
	viper.AddConfigPath("./testdata/")
	viper.AddConfigPath("./config/")
	viper.AddConfigPath(loadPath)
	viper.AddConfigPath(".")
	viper.AddConfigPath("..")
	err := viper.ReadInConfig()
	if err != nil {
		log.Fatal(err)
	}
	config.SmartContractConfig = cviper.GetViper()
	validateConfig()
}

func validateConfig() {
	if 0 >= viper.GetInt(bk.AvailableKeys) {
		log.Fatal(fmt.Errorf("avalable keys %d must be grater than zero",
			viper.GetInt(bk.AvailableKeys)))
	}

	if viper.GetInt(bk.NumClients) < viper.GetInt(bk.AvailableKeys) {
		log.Fatal(fmt.Errorf("number of clients %d less than avalable keys %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.AvailableKeys)))
	}

	if viper.GetInt(bk.NumClients) < viper.GetInt(bk.NumActiveClients) {
		log.Fatal(fmt.Errorf("number of clients %d less than then number of active clients %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.NumActiveClients)))
	}

	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumMiners) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of miners %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumMiners)))
	}

	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumSharders) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of sharders %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumSharders)))
	}

	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumMinerDelegates) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of minter delegates %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumMinerDelegates)))
	}
	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumSharderDelegates) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of sharder delegates %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumSharderDelegates)))
	}
	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumAllocationPayerPools) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of allocation pools %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumAllocationPayerPools)))
	}
	if viper.GetInt(bk.NumActiveClients) < viper.GetInt(bk.NumAllocationPayer) {
		log.Fatal(fmt.Errorf("number of active clients %d less than then number of allocation pools %d",
			viper.GetInt(bk.NumActiveClients), viper.GetInt(bk.NumAllocationPayer)))
	}

	if viper.GetInt(bk.NumBlobbersPerAllocation) > viper.GetInt(bk.NumBlobbers) {
		log.Fatal(fmt.Errorf("number of blobber per allocation %d grater than avalable blobbers %d",
			viper.GetInt(bk.NumBlobbersPerAllocation), viper.GetInt(bk.NumBlobbers)))
	}

	if viper.GetInt(bk.NumClients) < viper.GetInt(bk.NumAuthorizers) {
		log.Fatal(fmt.Errorf("number of clients %d less than authorisers %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.NumAuthorizers)))
	}

	if viper.GetInt(bk.NumClients) <= multisigsc.MaxSigners {
		log.Fatal(fmt.Errorf("number of clients %d must be greater than multi sig max singers %d",
			viper.GetInt(bk.NumClients), multisigsc.MaxSigners))
	}

	if viper.GetInt(bk.NumBlobberDelegates) > viper.GetInt(bk.NumActiveClients) {
		log.Fatal(fmt.Errorf("blolbber delegates %d cannot exceed active clients %d",
			viper.GetInt(bk.NumBlobberDelegates), viper.GetInt(bk.NumActiveClients)))
	}

	if viper.GetInt(bk.NumClients) > viper.GetInt(bk.NumAllocations) {
		log.Fatal(fmt.Errorf("number of clients %d must not exceed the number of allocations %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.NumAllocations)))
	}

	if viper.GetInt(bk.NumClients) < viper.GetInt(bk.NumMiners) {
		log.Fatal(fmt.Errorf("number of clients %d must be at least the number of miners %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.NumMiners)))
	}

	if viper.GetInt(bk.NumClients) < viper.GetInt(bk.NumSharders) {
		log.Fatal(fmt.Errorf("number of clients %d must be at least the number of sharders %d",
			viper.GetInt(bk.NumClients), viper.GetInt(bk.NumSharders)))
	}

	if viper.GetInt(bk.NumActiveMiners) > viper.GetInt(bk.NumMiners) {
		log.Fatal(fmt.Errorf("number of active miners %d cannot exceeed the number of miners %d",
			viper.GetInt(bk.NumActiveMiners), viper.GetInt(bk.NumMiners)))
	}

	if viper.GetInt(bk.NumActiveMiners) > viper.GetInt(bk.NumMiners) {
		log.Fatal(fmt.Errorf("number of active miners %d cannot exceed the number of miners %d",
			viper.GetInt(bk.NumActiveMiners), viper.GetInt(bk.NumMiners)))
	}

	if viper.GetInt(bk.NumActiveSharders) > viper.GetInt(bk.NumSharders) {
		log.Fatal(fmt.Errorf("number of active sharders %d cannot exceed the number of sharders %d",
			viper.GetInt(bk.NumActiveSharders), viper.GetInt(bk.NumSharders)))
	}
	if viper.GetInt(bk.BenchDataListLength) <= 0 {
		log.Fatal(fmt.Errorf("bench_data_list_length %d, must be greater than zero", viper.GetInt(bk.BenchDataListLength)))
	}
	if viper.GetInt(bk.BenchDataListLength) <= viper.GetInt(bk.NumAuthorizers) {
		log.Fatal(fmt.Errorf("bench data list length %v must be strickly greater than authorizer count %v",
			viper.GetInt(bk.BenchDataListLength), viper.GetInt(bk.NumAuthorizers)))
	}
	if viper.GetInt(bk.NumBlobbersPerAllocation) > viper.GetInt(bk.BenchDataListLength) {
		log.Fatal(fmt.Errorf("blobbers per allocation %d must not exceed the bench data length %d",
			viper.GetInt(bk.NumBlobbersPerAllocation), viper.GetInt(bk.BenchDataListLength)))
	}

	if viper.GetInt(bk.NumValidators) < viper.GetInt(bk.StorageValidatorsPerChallenge) {
		log.Fatal(fmt.Errorf("validators %d must be at least equal in number to the validators per challenge %d",
			viper.GetInt(bk.NumValidators), viper.GetInt(bk.StorageValidatorsPerChallenge)))
	}

	if viper.GetInt(bk.BenchDataListLength) < multisigsc.MaxSigners {
		log.Fatal(fmt.Errorf("mulitsinc max signers %d must not exceed the bench data length %d",
			multisigsc.MaxSigners, viper.GetInt(bk.BenchDataListLength)))
	}

	if viper.GetInt64(bk.NumAllocations) > viper.GetInt64(bk.NumBlocks) {
		log.Fatal(fmt.Errorf("number of allocations %d can't exceed the number of blocks %d",
			viper.GetInt64(bk.NumAllocations), viper.GetInt64(bk.NumBlocks)))
	}

}
