package core

import (
	"context"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/schrodinger/pkg/storage"
	"github.com/pingcap/schrodinger/pkg/types"
)

// GetCat gets cat
func (mgr *Manager) GetCat(catID int64) (*types.CatProcess, bool) {
	return mgr.storage.GetCatProcess(catID)
}

// GetCatByName gets cat by name
func (mgr *Manager) GetCatByName(catName string) (*types.CatProcess, bool) {
	return mgr.storage.GetCatProcessByName(catName)
}

// ListCat lists cats
func (mgr *Manager) ListCat(condition *storage.CatProcessConditions) (types.CatProcesses, int64) {
	return mgr.storage.ListCatProcess(condition)
}

// UpgradeCat upgrade cat
func (mgr *Manager) UpgradeCat(catID int64, config *types.Cat, waitOk bool) error {
	if waitOk {
		return mgr.catCtrl.UpgradeCat(catID, config)
	}

	go func() {
		if err := mgr.catCtrl.UpgradeCat(catID, config); err != nil {
			log.Errorf("upgrade cat : %d / error : %v", catID, err)
		}
	}()

	return nil
}

// CreateCat creates cat
func (mgr *Manager) CreateCat(config *types.Cat, waitOk bool) (*types.CatProcess, error) {
	namespace := genCatNamespace(config)
	catName := config.Name
	catProcess := types.GenCatProcess(catName, namespace, config)
	err := mgr.storage.CreateCatProcess(catProcess)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if waitOk {
		if _, err := mgr.catCtrl.StartCat(context.Background(), catProcess); err != nil {
			log.Errorf("start cat : %+v / error : %v", catProcess, errors.ErrorStack(err))
			return nil, errors.Trace(err)
		}
		return catProcess, nil
	}

	go func() {
		if _, err := mgr.catCtrl.StartCat(context.Background(), catProcess); err != nil {
			log.Errorf("start cat : %+v / error : %v", catProcess, errors.ErrorStack(err))
		}
	}()
	return catProcess, nil
}

// DestroyCat stops cat
func (mgr *Manager) DestroyCat(catID int64) error {
	return errors.Trace(mgr.catCtrl.DestroyCat(catID))
}

// BackupCat backups cat physically
func (mgr *Manager) BackupCat(catID int64, backupName string) error {
	return errors.Trace(mgr.catCtrl.BackupCat(catID, backupName))
}

// RestoreCat restores cat with a physical backup
func (mgr *Manager) RestoreCat(catID int64, backupName string) error {
	return errors.Trace(mgr.catCtrl.RestoreCat(catID, backupName))
}

// GetCatStatus returns the stage of cat
func (mgr *Manager) GetCatStatus(catID int64) (types.CatStatus, error) {
	return mgr.catCtrl.GetCatStatus(catID)
}

// ListCatBackups returns all backups of the cat
func (mgr *Manager) ListCatBackups(catID int64) ([]*types.TiDBClusterBackup, error) {
	return mgr.catCtrl.ListCatBackups(catID)
}

// ListCatConfigTemplates returns all config templates
func (mgr *Manager) ListCatConfigTemplates() (types.TiDBClusterConfigTemplates, error) {
	return mgr.storage.ListTiDBClusterConfigTemplates(), nil
}

// GetCatConfigTemplatesByTag returns all config templates by tag
func (mgr *Manager) GetCatConfigTemplatesByTag(tag string) (types.TiDBClusterConfigTemplates, error) {
	return mgr.storage.GetTiDBClusterConfigTemplateByTag(tag), nil
}

// GetCatConfigTemplate returns config template by id
func (mgr *Manager) GetCatConfigTemplate(id int64) (*types.TiDBClusterConfigTemplate, error) {
	tpl, ok := mgr.storage.GetTiDBClusterConfigTemplate(id)
	if !ok {
		return nil, errors.NotFoundf("config template %d", id)
	}

	return tpl, nil
}

// GetCatConfigTemplateByName returns config template by name
func (mgr *Manager) GetCatConfigTemplateByName(name string) (*types.TiDBClusterConfigTemplate, error) {
	tpl, ok := mgr.storage.GetTiDBClusterConfigTemplateByName(name)
	if !ok {
		return nil, errors.NotFoundf("config template %s", name)
	}

	return tpl, nil
}

// CreateCatConfigTemplate creates a new config template
func (mgr *Manager) CreateCatConfigTemplate(tpl *types.TiDBClusterConfigTemplate) error {
	return errors.Trace(mgr.storage.CreateTiDBClusterConfigTemplate(tpl))
}

// UpdateCatConfigTemplate update config template
func (mgr *Manager) UpdateCatConfigTemplate(tpl *types.TiDBClusterConfigTemplate) error {
	return errors.Trace(mgr.storage.UpdateTiDBClusterConfigTemplate(tpl))
}

// DeleteCatConfigTemplate deletes config template
func (mgr *Manager) DeleteCatConfigTemplate(id int64) error {
	return errors.Trace(mgr.storage.DeleteTiDBClusterConfigTemplate(id))
}
