package dbdsn

import (
	"testing"
	"time"

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

func TestDefaultMySQLParseTime(t *testing.T) {
	tests := []struct {
		name          string
		dsn           string
		wantParseTime bool
	}{
		{name: "empty DSN defaults true", dsn: "", wantParseTime: true},
		{name: "missing without query defaults true", dsn: "user:p?ass@tcp(host:3306)/db", wantParseTime: true},
		{name: "empty query defaults true", dsn: "user:pass@tcp(host:3306)/db?", wantParseTime: true},
		{
			name:          "missing defaults true",
			dsn:           "user:pass@tcp(host:3306)/db?loc=Asia%2FShanghai&timeout=5s&sql_mode=TRADITIONAL",
			wantParseTime: true,
		},
		{name: "explicit true preserved", dsn: "user:pass@tcp(host:3306)/db?parseTime=true", wantParseTime: true},
		{name: "explicit false preserved", dsn: "user:pass@tcp(host:3306)/db?parseTime=false&timeout=5s", wantParseTime: false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg, err := driversql.ParseDSN(DefaultMySQLParseTime(tt.dsn))
			if err != nil {
				t.Fatalf("parse normalized DSN: %v", err)
			}
			if cfg.ParseTime != tt.wantParseTime {
				t.Fatalf("ParseTime = %v, want %v", cfg.ParseTime, tt.wantParseTime)
			}
		})
	}
}

func TestDefaultMySQLParseTimePreservesConfig(t *testing.T) {
	const dsn = "user:pass@tcp(host:3306)/db?loc=Asia%2FShanghai&timeout=5s&sql_mode=TRADITIONAL"
	cfg, err := driversql.ParseDSN(DefaultMySQLParseTime(dsn))
	if err != nil {
		t.Fatalf("parse normalized DSN: %v", err)
	}

	if cfg.User != "user" || cfg.Passwd != "pass" || cfg.Net != "tcp" || cfg.Addr != "host:3306" || cfg.DBName != "db" {
		t.Fatalf("connection config changed: %#v", cfg)
	}
	if cfg.Loc.String() != "Asia/Shanghai" {
		t.Fatalf("location = %q, want Asia/Shanghai", cfg.Loc)
	}
	if cfg.Timeout != 5*time.Second {
		t.Fatalf("timeout = %v, want 5s", cfg.Timeout)
	}
	if cfg.Params["sql_mode"] != "TRADITIONAL" {
		t.Fatalf("sql_mode = %q, want TRADITIONAL", cfg.Params["sql_mode"])
	}
}

func TestDefaultMySQLParseTimeIsIdempotent(t *testing.T) {
	tests := []string{
		"user:pass@tcp(host:3306)/db",
		"user:pass@tcp(host:3306)/db?parseTime=true&timeout=5s",
		"user:pass@tcp(host:3306)/db?parseTime=false&timeout=5s",
	}

	for _, dsn := range tests {
		once := DefaultMySQLParseTime(dsn)
		if twice := DefaultMySQLParseTime(once); twice != once {
			t.Fatalf("DefaultMySQLParseTime is not idempotent for %q: once %q, twice %q", dsn, once, twice)
		}
	}
}

func TestDefaultMySQLParseTimeLeavesInvalidDSNUnchanged(t *testing.T) {
	const dsn = "invalid://dsn"
	if got := DefaultMySQLParseTime(dsn); got != dsn {
		t.Fatalf("DefaultMySQLParseTime(%q) = %q, want unchanged", dsn, got)
	}
}
