package gormutil_test

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"testing"

	"github.com/pingcap/dbaas/pkg/docker_db/db/iface"
	"github.com/pingcap/dbaas/pkg/gormutil"
	"github.com/pingcap/errors"
	_ "gorm.io/driver/mysql"
)

var db *sql.DB

func connect(host string, port int) error {
	var err error
	dsn := fmt.Sprintf("root:@(%s:%d)/test?charset=utf8mb4&parseTime=True&loc=UTC&timeout=30s&readTimeout=30s&writeTimeout=30s", host, port)
	db, err = sql.Open("mysql", dsn)
	if err == nil {
		_, err = db.Exec("SHOW TABLES")
	}
	return errors.Annotatef(err, "MySQL connection failure %s:%d", host, port)
}

func init() {
	// ./hack/start-db-server does not use the host network
	host := "127.0.0.1"
	port := 21000
	if err := connect(host, port); err == nil {
		return
	}

	port = 4000
	rsp, err := http.Get("http://localhost:11234/info")
	if err != nil {
		log.Fatal(err)
	}
	if rsp.Body != nil {
		defer rsp.Body.Close() // nolint
	}
	contents, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		log.Fatal(err)
	}

	dbMap := map[string]*iface.DockerDB{}
	if err := json.Unmarshal(contents, &dbMap); err != nil {
		log.Fatal(fmt.Sprintf("%s: %s", err.Error(), string(contents)))
	}

	for _, db := range dbMap {
		host = db.IP
	}
	if err := connect(host, port); err != nil {
		log.Fatal(err)
	}
}

func createUser(user string, password string) error {
	if _, err := db.Exec(fmt.Sprintf("DROP USER IF EXISTS '%s'@'%%'", user)); err != nil {
		return errors.Annotate(err, "DROP USER")
	}
	_, err := db.Exec(fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s'", user, password))
	return errors.Annotate(err, "CREATE USER")
}

func TestEscape(t *testing.T) {
	passwordUnescaped := `'\`
	password := gormutil.Escape(passwordUnescaped)
	if err := createUser("test1", password); err != nil {
		fmt.Println("Failed to set password")
		panic(err)
	}
	if err := createUser("test2", passwordUnescaped); err == nil {
		panic("expected SQL syntax error")
	}
}
