package snapshot

import (
	"encoding/base64"
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDmVerityInfoValidation(t *testing.T) {
	TestData := []DmVerityInfo{
		{
			HashType:  "md5", // "md5" is not a supported hash algorithm
			Blocksize: 512,
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 3000, // Invalid block size, not a power of 2.
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 0, // Invalid block size, less than 512.
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 524800, // Invalid block size, greater than 524288.
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  3000, // Invalid hash block size, not a power of 2.
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  0, // Invalid hash block size, less than 512.
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  524800, // Invalid hash block size, greater than 524288.
			BlockNum:  16384,
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  512,
			BlockNum:  0, // Invalid BlockNum, it must be greater than 0.
			Offset:    8388608,
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    0, // Invalid offset, it must be greater than 0.
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8193, // Invalid offset, it must be aligned to 512.
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
		{
			HashType:  "sha256",
			Blocksize: 512,
			Hashsize:  512,
			BlockNum:  16384,
			Offset:    8388608 - 4096, // Invalid offset, it must be equal to blocksize * BlockNum.
			Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
		},
	}

	for _, d := range TestData {
		assert.Error(t, d.Validate())
	}
	TestCorrectData := DmVerityInfo{
		HashType:  "sha256",
		Blocksize: 512,
		Hashsize:  512,
		BlockNum:  16384,
		Offset:    8388608,
		Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
	}
	assert.NoError(t, TestCorrectData.Validate())
}

func TestDirectAssignedVolumeValidation(t *testing.T) {
	validDirectVolume := DirectAssignedVolume{
		Metadata: map[string]string{"key": "value"},
	}
	assert.True(t, validDirectVolume.Validate())

	invalidDirectVolume := DirectAssignedVolume{
		Metadata: nil,
	}
	assert.False(t, invalidDirectVolume.Validate())
}

func TestImagePullVolumeValidation(t *testing.T) {
	validImagePull := ImagePullVolume{
		Metadata: map[string]string{"key": "value"},
	}
	assert.True(t, validImagePull.Validate())

	invalidImagePull := ImagePullVolume{
		Metadata: nil,
	}
	assert.False(t, invalidImagePull.Validate())
}

func TestNydusImageVolumeValidation(t *testing.T) {
	validNydusImage := NydusImageVolume{
		Config:      "config_value",
		SnapshotDir: "",
	}
	assert.True(t, validNydusImage.Validate())

	invalidNydusImage := NydusImageVolume{
		Config:      "",
		SnapshotDir: "",
	}
	assert.False(t, invalidNydusImage.Validate())
}

func TestKataVirtualVolumeValidation(t *testing.T) {
	validKataVirtualVolume := KataVirtualVolume{
		VolumeType: "direct_block",
		Source:     "/dev/sdb",
		FSType:     "ext4",
		Options:    []string{"rw"},
		DirectVolume: &DirectAssignedVolume{
			Metadata: map[string]string{"key": "value"},
		},
		// Initialize other fields
	}
	assert.True(t, validKataVirtualVolume.Validate())

	invalidKataVirtualVolume := KataVirtualVolume{
		VolumeType: "direct_block",
		Source:     "/dev/sdb",
		FSType:     "",
		Options:    nil,
		DirectVolume: &DirectAssignedVolume{
			Metadata: nil,
		},
		// Initialize other fields
	}
	assert.False(t, invalidKataVirtualVolume.Validate())
}
func TestParseDmVerityInfo(t *testing.T) {
	// Create a mock valid KataVirtualVolume
	validDmVerityInfo := DmVerityInfo{
		HashType:  "sha256",
		Blocksize: 512,
		Hashsize:  512,
		BlockNum:  16384,
		Offset:    8388608,
		Hash:      "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
	}
	validKataVirtualVolumeJSON, _ := json.Marshal(validDmVerityInfo)

	t.Run("Valid Option", func(t *testing.T) {
		volume, err := ParseDmVerityInfo(string(validKataVirtualVolumeJSON))
		assert.NoError(t, err)
		assert.NotNil(t, volume)
		assert.NoError(t, volume.Validate())
	})

	t.Run("Invalid JSON Option", func(t *testing.T) {
		volume, err := ParseDmVerityInfo("invalid_json")
		assert.Error(t, err)
		assert.Nil(t, volume)
	})

}
func TestParseKataVirtualVolume(t *testing.T) {
	// Create a mock valid KataVirtualVolume
	validKataVirtualVolume := KataVirtualVolume{
		VolumeType: "direct_block",
		Source:     "/dev/sdb",
		FSType:     "ext4",
		Options:    []string{"rw"},
		DirectVolume: &DirectAssignedVolume{
			Metadata: map[string]string{"key": "value"},
		},
		// Initialize other fields
	}
	validOption, err := EncodeKataVirtualVolumeToBase64(validKataVirtualVolume)
	assert.Nil(t, err)

	t.Run("Valid Option", func(t *testing.T) {
		volume, err := ParseKataVirtualVolumeFromBase64(validOption)

		assert.NoError(t, err)
		assert.NotNil(t, volume)
		assert.True(t, volume.Validate())
	})

	t.Run("Invalid JSON Option", func(t *testing.T) {
		invalidJSONOption := base64.StdEncoding.EncodeToString([]byte("invalid_json"))
		volume, err := ParseKataVirtualVolumeFromBase64(invalidJSONOption)

		assert.Error(t, err)
		assert.Nil(t, volume)
	})

	invalidBase64Option := "invalid_base64"
	t.Run("Invalid Base64 Option", func(t *testing.T) {
		volume, err := ParseKataVirtualVolumeFromBase64(invalidBase64Option)

		assert.Error(t, err)
		assert.Nil(t, volume)
	})

	t.Run("Invalid Fields", func(t *testing.T) {
		// Create a mock invalid KataVirtualVolume
		validKataVirtualVolume = KataVirtualVolume{
			VolumeType: "direct_block",
			Source:     "/dev/sdb",
			FSType:     "ext4",
			Options:    []string{"rw"},
			// Initialize other fields
		}
		invalidFieldOption, err := EncodeKataVirtualVolumeToBase64(validKataVirtualVolume)
		assert.Nil(t, err)
		volume, err := ParseKataVirtualVolumeFromBase64(invalidFieldOption)
		assert.Error(t, err)
		assert.Nil(t, volume)
	})
}
