package util

import (
	"database/sql"
	"fmt"
	"time"

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

// CreateReplication creates replication. return the addresses of each db
// count is how many db setup (but now not support more then 2)
// typ now just support now	"github.com/pingcap/schrodinger/pkg/types.MysqlType"
// version is mysql version. support 5.6/5.7/8.0
// id is initial index for node
func CreateReplication(cli *client.Client, count int, typ types.Type, version string, id int) ([]string, error) {
	var hosts []string
	if count != 2 {
		return nil, errors.NotSupportedf("count must be equal to 2")
	}
	for i := 1; i <= count; i++ {
		host, err := SetUpDB(cli, typ, version, id+i)
		if err != nil {
			return nil, errors.Trace(err)
		}
		hosts = append(hosts, host)
	}

	time.Sleep(2 * time.Minute)
	err := createReplicate(hosts, typ)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return hosts, nil
}

func createReplicate(hosts []string, typ types.Type) error {
	var dbs []*sql.DB
	for _, host := range hosts {
		dbDSN := fmt.Sprintf("root:@tcp(%s:3306)/performance_schema", host)
		db, err := OpenDB(dbDSN, 2)
		if err != nil {
			return errors.Trace(err)
		}
		dbs = append(dbs, db)
	}

	// on server 1/server2
	sql := "create user 'replicator'@'%' identified by 'password';"
	for _, db := range dbs {
		_, err := db.Exec(sql)
		if err != nil {
			return errors.Trace(err)
		}
	}

	// server ids must be different for replication to work
	sql = "SET @@GLOBAL.SERVER_ID = %d"
	for idx, db := range dbs {
		_, err := db.Exec(fmt.Sprintf(sql, 100+idx))
		if err != nil {
			return errors.Trace(err)
		}
	}

	sql = "grant replication slave on *.* to 'replicator'@'%';"
	for _, db := range dbs {
		_, err := db.Exec(sql)
		if err != nil {
			return errors.Trace(err)
		}
	}

	meta, err := GetMasterPos(dbs[0], typ)
	if err != nil {
		return errors.Trace(err)
	}

	for index, host := range hosts {
		sqls := []string{
			"stop slave;",
			fmt.Sprintf("CHANGE MASTER TO MASTER_HOST = '%s', MASTER_USER = 'replicator', MASTER_PASSWORD = 'password', MASTER_LOG_FILE = '%s', MASTER_LOG_POS = %d;", host, meta.BinLogName, meta.BinLogPos),
			"start slave;",
		}

		for _, sql := range sqls {
			db := dbs[0]
			if index == 0 {
				db = dbs[1]
			}
			_, err = db.Exec(sql)
			if err != nil {
				client.Debug(sql)
				return errors.Trace(err)
			}
		}
	}

	return nil
}
