package config

import (
	"testing"

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

// 구조화된 db 설정으로 postgres DSN(key=value 형식)을 조립한다.
// 비밀번호의 공백/따옴표 등 특수문자는 에이전트가 이스케이프한다.
func TestPostgresDSNFromStructured(t *testing.T) {
	cases := []struct {
		name string
		cfg  ServiceConfig
		want string
	}{
		{
			"전체 지정",
			ServiceConfig{Type: "postgres", DB: &DBConn{
				Host: "db.internal", Port: 5433, User: "monitor",
				Password: "plain", DBName: "payment", SSLMode: "require",
			}},
			"host=db.internal port=5433 user=monitor password=plain dbname=payment sslmode=require",
		},
		{
			"기본값 보정 (host/port/sslmode/dbname)",
			ServiceConfig{Type: "postgres", DB: &DBConn{User: "monitor", Password: "pw"}},
			"host=localhost port=5432 user=monitor password=pw dbname=postgres sslmode=disable",
		},
		{
			"특수문자 비밀번호는 따옴표로 감싸고 이스케이프",
			ServiceConfig{Type: "postgres", DB: &DBConn{
				User: "monitor", Password: `p@ss 'wo\rd`, DBName: "app",
			}},
			`host=localhost port=5432 user=monitor password='p@ss \'wo\\rd' dbname=app sslmode=disable`,
		},
	}
	for _, c := range cases {
		if got := c.cfg.PostgresDSN(); got != c.want {
			t.Errorf("%s:\n got  %s\n want %s", c.name, got, c.want)
		}
	}
}

// db 객체가 없으면 기존 dsn 문자열을 그대로 사용한다(하위 호환).
func TestDSNFallbackToString(t *testing.T) {
	pg := ServiceConfig{Type: "postgres", DSN: "postgres://u:p@h:5432/d"}
	if got := pg.PostgresDSN(); got != "postgres://u:p@h:5432/d" {
		t.Errorf("postgres dsn 폴백 실패: %s", got)
	}
	my := ServiceConfig{Type: "mysql", DSN: "u:p@tcp(h:3306)/d"}
	if got := my.MySQLDSN(); got != "u:p@tcp(h:3306)/d" {
		t.Errorf("mysql dsn 폴백 실패: %s", got)
	}
}

// 구조화된 db 설정으로 만든 mysql DSN은 특수문자 비밀번호가 있어도
// 드라이버 파서로 원래 값 그대로 복원돼야 한다(라운드트립).
func TestMySQLDSNFromStructured(t *testing.T) {
	cfg := ServiceConfig{Type: "mysql", DB: &DBConn{
		Host: "db.internal", Port: 3307, User: "monitor",
		Password: "p@ss/w:rd", DBName: "orders",
	}}
	dsn := cfg.MySQLDSN()
	parsed, err := mysql.ParseDSN(dsn)
	if err != nil {
		t.Fatalf("생성된 DSN 파싱 실패: %v (dsn=%s)", err, dsn)
	}
	if parsed.User != "monitor" || parsed.Passwd != "p@ss/w:rd" ||
		parsed.Addr != "db.internal:3307" || parsed.DBName != "orders" {
		t.Errorf("라운드트립 불일치: %+v", parsed)
	}

	// 기본값 보정: host/port 미지정 → localhost:3306
	def := ServiceConfig{Type: "mysql", DB: &DBConn{User: "monitor", Password: "pw"}}
	p2, err := mysql.ParseDSN(def.MySQLDSN())
	if err != nil {
		t.Fatal(err)
	}
	if p2.Addr != "localhost:3306" {
		t.Errorf("기본 주소 localhost:3306 기대, got %s", p2.Addr)
	}
}
