package connectorfixture

import (
	"context"
	"database/sql"
	"fmt"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/go-sql-driver/mysql"
)

// OpenTiDB creates an isolated database; it never reuses a configured database.
func OpenTiDB(t testing.TB) *sql.DB {
	t.Helper()
	cfg, err := tiDBConfig()
	if err != nil {
		t.Fatal(err)
	}
	admin, err := sql.Open("mysql", cfg.FormatDSN())
	if err != nil {
		t.Fatal(err)
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err = admin.PingContext(ctx); err != nil {
		admin.Close()
		if os.Getenv("NEXUSCRM_TIDB_REQUIRED") == "1" {
			t.Fatalf("required TiDB unavailable: %v", err)
		}
		t.Skipf("TiDB unavailable: %v", err)
	}
	name := fmt.Sprintf("nexuscrm_projection_%d", time.Now().UnixNano())
	if _, err = admin.ExecContext(ctx, "CREATE DATABASE "+quote(name)); err != nil {
		admin.Close()
		t.Fatal(err)
	}
	cfg.DBName = name
	db, err := sql.Open("mysql", cfg.FormatDSN())
	t.Cleanup(func() {
		if db != nil {
			db.Close()
		}
		admin.Exec("DROP DATABASE " + quote(name))
		admin.Close()
	})
	if err != nil {
		t.Fatal(err)
	}
	return db
}

// Keep the connection policy shared by the administrative and isolated-test
// connections. TLS requests never allow a plaintext fallback.
func tiDBConfig() (*mysql.Config, error) {
	host, port := os.Getenv("TIDB_HOST"), os.Getenv("TIDB_PORT")
	if host == "" {
		host = "127.0.0.1"
	}
	if port == "" {
		port = "4001"
	}
	user := os.Getenv("TIDB_USER")
	if user == "" {
		user = "root"
	}
	cfg := mysql.NewConfig()
	cfg.User = user
	cfg.Passwd = os.Getenv("TIDB_PASSWORD")
	cfg.Net = "tcp"
	cfg.Addr = host + ":" + port
	cfg.ParseTime = true
	cfg.Loc = time.UTC
	cfg.Timeout = 5 * time.Second
	switch value := strings.ToLower(strings.TrimSpace(os.Getenv("TIDB_TLS"))); value {
	case "", "0", "false", "f":
	case "1", "true", "t", "yes", "require", "verify-full":
		cfg.TLSConfig = "true"
	default:
		return nil, fmt.Errorf("unsupported TIDB_TLS value %q", value)
	}
	return cfg, nil
}
