package schema

import (
	"context"
	"reflect"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"gorm.io/gorm"
)

// Versioned provides the versioning for model, auto increment the version when update/save
// foo := &Foo{}
// 1. [don't support]batch save/create: db.Save([]*Foo{foo})
// 2. [ok]save one: db.Save(foo)
// 3. [ok]update one field: db.Model(foo).Update("a", 1)
// 4. [ok]update multiple fields: db.Model(foo).Updates(map[string]interface{}{"a": 1, "b": 2})
// 5. [ok]update by model: db.Model(foo}).Select("*").Updates(foo)
type Versioned struct {
	Versioning int `gorm:"versioning; default:1"`
}

type IdAndVersioning interface {
	GetId() uint64
	GetVersioning() int
}

var (
	_ IdAndVersioning = (*Cluster)(nil)
	_ IdAndVersioning = (*BackupSetting)(nil)
	_ IdAndVersioning = (*Backup)(nil)
	_ IdAndVersioning = (*Restore)(nil)
	_ IdAndVersioning = (*Export)(nil)
)

func (u *Versioned) GetVersioning() int {
	return u.Versioning
}

func (c *Cluster) GetId() uint64 {
	return c.ID
}

func (b *BackupSetting) GetId() uint64 {
	return b.ID
}

func (b *Backup) GetId() uint64 {
	return b.ID
}

func (r *Restore) GetId() uint64 {
	return r.ID
}

func (e *Export) GetId() uint64 {
	return uint64(e.ID)
}

func (u *Versioned) BeforeUpdate(tx *gorm.DB) (err error) {
	// should go here if we use db.Save(model)/db.Updates(model)
	if u.Versioning != 0 {
		tx.Statement.SetColumn("versioning", u.Versioning+1)
	} else { // should go here if we use db.Update(k,v)/db.Updates(map)
		logger := tilog.WithContextS(context.Background())
		// TODO: Sentry
		logger.Infof("detected use db.Update(k,v) or db.Updates(map), model=%s", reflect.TypeOf(tx.Statement.Model))

		tx.Statement.SetColumn("versioning", gorm.Expr("versioning + 1"))
	}
	return nil
}
