package transactional_operation

import (
	"database/sql"
	"strings"
	"validate/dbctrl"
	"validate/util"
)

func exportDBAccountDefinition(dbAccountName string, tx *sql.Tx) (*dbctrl.DBAccountInfo, error) {
	var dbAccountCreationStmt, dbAccountGrantStmt string

	dbAccountCreationStmt, err := dbctrl.ShowCreateDBAccount(dbAccountName, tx)
	if err != nil {
		return nil, err
	}

	dbAccountGrantStmt, err = dbctrl.ShowGrantDBAccount(dbAccountName, tx)
	if err != nil {
		return nil, err
	}

	return &dbctrl.DBAccountInfo{
		Name:       dbAccountName,
		CreateStmt: dbAccountCreationStmt,
		GrantStmt:  dbAccountGrantStmt}, nil
}

func exportRootRecoveryStmt(tx *sql.Tx) (*dbctrl.DBAccountInfo, error) {
	dbAccount, err := exportDBAccountDefinition("root", tx)
	if err != nil {
		return nil, err
	}

	dbAccount.CreateStmt = strings.Replace(dbAccount.CreateStmt, "CREATE", "ALTER", 1)

	return dbAccount, nil
}

func ExportAllDBUserDefinition(db *sql.DB) (dbAccountList []*dbctrl.DBAccountInfo, err error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	defer func() {
		commitErr := tx.Commit()
		if commitErr != nil {
			util.Logger.Fatalf("failed to COMMIT transaction, " + commitErr.Error())
		}
	}()

	dbAccountNameList, err := dbctrl.GetAllDBAccount(tx)
	if err != nil {
		return nil, err
	}
	for _, dbAccountName := range dbAccountNameList {
		dbAccount, err := exportDBAccountDefinition(dbAccountName, tx)
		if err != nil {
			rollbackErr := tx.Rollback()
			if rollbackErr != nil {
				util.Logger.Fatalf("failed to ROLLBACK transaction, " + rollbackErr.Error())
			}
			return nil, err
		}

		dbAccountList = append(dbAccountList, dbAccount)
	}

	root, err := exportRootRecoveryStmt(tx)
	if err != nil {
		rollbackErr := tx.Rollback()
		if rollbackErr != nil {
			util.Logger.Fatalf("failed to ROLLBACK transaction, " + rollbackErr.Error())
		}
		return dbAccountList, err
	}
	dbAccountList = append(dbAccountList, root)

	return dbAccountList, nil
}
