package storage

import (
	"reflect"

	"github.com/juju/errors"
	. "github.com/pingcap/check"
	"github.com/pingcap/schrodinger/pkg/types"
)

var _ = Suite(&clusterBackupSuite{})

type clusterBackupSuite struct {
	store *Storage
}

func (t *clusterBackupSuite) SetUpTest(c *C) {
	t.store = setupStore("cluster_backup")
}

func (t *clusterBackupSuite) TearDownSuite(c *C) {
	t.store.Close()
}

func (t *clusterBackupSuite) TestCreateTiDBClusterBackup(c *C) {
	if err := t.store.CreateTiDBClusterBackup(insertTiDBClusterBackup); err != nil {
		c.Fatalf("creating TiDB cluster backup fails: %s", errors.ErrorStack(err))
	}

	if insertTiDBClusterBackup.ID == 0 {
		c.Fatalf("expect non zero ID, got %d", insertTiDBClusterBackup.ID)
	}

	got, exists := t.store.GetTiDBClusterBackup(insertTiDBClusterBackup.ID)
	c.Assert(exists, Equals, true)

	if !reflect.DeepEqual(insertTiDBClusterBackup, got) {
		c.Fatalf("expect %v, got %v", *insertTiDBClusterBackup, *got)
	}
}

func (t *clusterBackupSuite) TestUpdateTiDBClusterBackup(c *C) {
	t.TestCreateTiDBClusterBackup(c)

	updateTiDBClusterBackup.ID = insertTiDBClusterBackup.ID
	updateTiDBClusterBackup.Ctime = insertTiDBClusterBackup.Ctime

	if err := t.store.UpdateTiDBClusterBackup(updateTiDBClusterBackup); err != nil {
		c.Fatalf("updating tidb cluster backup fails: %s", errors.ErrorStack(err))
	}

	got, exists := t.store.GetTiDBClusterBackup(updateTiDBClusterBackup.ID)
	c.Assert(exists, Equals, true)
	updateTiDBClusterBackup.Utime = got.Utime

	if !reflect.DeepEqual(updateTiDBClusterBackup, got) {
		c.Fatalf("expect %v, got %v", *updateTiDBClusterBackup, *got)
	}
}

func (t *clusterBackupSuite) TestGetTiDBClusterBackupByID(c *C) {
	t.TestCreateTiDBClusterBackup(c)

	got, exists := t.store.GetTiDBClusterBackup(insertTiDBClusterBackup.ID)
	c.Assert(exists, Equals, true)
	if !reflect.DeepEqual(insertTiDBClusterBackup, got) {
		c.Fatalf("expect %v, got %v", *insertTiDBClusterBackup, *got)
	}
}

func (t *clusterBackupSuite) TestGetTiDBClusterBackupByCatIDAndName(c *C) {
	t.TestCreateTiDBClusterBackup(c)

	got, exists := t.store.GetTiDBClusterBackupByCatIDAndName(insertTiDBClusterBackup.CatID, insertTiDBClusterBackup.Name)
	c.Assert(exists, Equals, true)

	if !reflect.DeepEqual(insertTiDBClusterBackup, got) {
		c.Fatalf("expect %v, got %v", *insertTiDBClusterBackup, *got)
	}
	_, exists = t.store.GetTiDBClusterBackupByCatIDAndName(1234567, insertTiDBClusterBackup.Name)
	c.Assert(exists, Equals, false)
}

func (t *clusterBackupSuite) TestGetTiDBClusterBackupByCatID(c *C) {
	t.TestCreateTiDBClusterBackup(c)

	got := t.store.GetTiDBClusterBackupsByCatID(insertTiDBClusterBackup.CatID)
	if !reflect.DeepEqual([]*types.TiDBClusterBackup{insertTiDBClusterBackup}, got) {
		c.Fatalf("expect [%v], got %v", *insertTiDBClusterBackup, got)
	}

	got = t.store.GetTiDBClusterBackupsByCatID(1234567)
	if len(got) != 0 {
		c.Fatalf("expect zero elements, got %v", got)
	}
}

var insertTiDBClusterBackup = &types.TiDBClusterBackup{
	Name:        "name",
	Namespace:   "namespace",
	ClusterName: "cluster name",
	CatID:       1,
	State:       "state",
	Spec: types.TiDBClusterBackupSpec{
		Cluster: "cluster",
		PhysicalBackup: &types.PhysicalBackupSpec{
			BackupMembers: []string{"member 1", "member 2"},
			BackupStores:  []string{"store1", "store2"},
		},
	},
	Status: types.TiDBClusterBackupStatus{
		PhysicalBackupStatus: types.PhysicalBackupStatus{
			TiKVBackupTaskStatuses: map[string]*types.BackupTaskStatus{
				"key": {
					TaskName:   "task name",
					ID:         "id",
					State:      types.BackupSuccess,
					Message:    "message",
					BackupNode: "backup node",
					BackupDir:  "backup dir",
					BeginTime:  "begin time",
					EndTime:    "end time",
				},
			},
			PDBackupTaskStatuses: map[string]*types.BackupTaskStatus{
				"key2": {
					TaskName:   "task name2",
					ID:         "id2",
					State:      types.BackupFailed,
					Message:    "message 2",
					BackupNode: "backup node 2",
					BackupDir:  "backup dir 2",
					BeginTime:  "begin time 2",
					EndTime:    "end time 2",
				},
			},
		},
	},
}

var updateTiDBClusterBackup = &types.TiDBClusterBackup{
	Name:        "name 2",
	Namespace:   "namespace 2",
	ClusterName: "cluster name 2",
	CatID:       2,
	State:       "state 2",
	Spec: types.TiDBClusterBackupSpec{
		Cluster: "cluster2",
		PhysicalBackup: &types.PhysicalBackupSpec{
			BackupMembers: []string{"member 1", "member 2", "member 3"},
			BackupStores:  []string{"store1", "store2", "store3"},
		},
	},
	Status: types.TiDBClusterBackupStatus{
		PhysicalBackupStatus: types.PhysicalBackupStatus{
			TiKVBackupTaskStatuses: map[string]*types.BackupTaskStatus{
				"key3": {
					TaskName:   "task name2",
					ID:         "id2",
					State:      types.BackupSuccess,
					Message:    "message 2",
					BackupNode: "backup node 2",
					BackupDir:  "backup dir 2",
					BeginTime:  "begin time 2",
					EndTime:    "end time 2",
				},
			},
			PDBackupTaskStatuses: map[string]*types.BackupTaskStatus{
				"key4": {
					TaskName:   "task name3",
					ID:         "id3",
					State:      types.BackupFailed,
					Message:    "message 3",
					BackupNode: "backup node 3",
					BackupDir:  "backup dir 3",
					BeginTime:  "begin time 3",
					EndTime:    "end time 3",
				},
			},
		},
	},
}
