package bootstrapimpl

import "testing"

func TestIsSafeAutoColumnTypeChangeAllowsGenericNumericWidening(t *testing.T) {
	cases := []struct {
		name     string
		existing string
		desired  string
	}{
		{
			name:     "int to decimal",
			existing: "int(11)",
			desired:  "DECIMAL(65,30)",
		},
		{
			name:     "int to bigint",
			existing: "INT",
			desired:  "BIGINT",
		},
		{
			name:     "decimal precision and scale widening",
			existing: "decimal(10,2)",
			desired:  "decimal(12,3)",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if !isAutoColumnTypeChangeSupported(tc.existing, tc.desired) {
				t.Fatalf("isAutoColumnTypeChangeSupported(%q, %q) = false, want true", tc.existing, tc.desired)
			}
		})
	}
}

func TestIsSafeAutoColumnTypeChangeRejectsUnsafeNumericChanges(t *testing.T) {
	cases := []struct {
		name     string
		existing string
		desired  string
	}{
		{
			name:     "decimal integer capacity narrowing",
			existing: "decimal(10,2)",
			desired:  "decimal(10,3)",
		},
		{
			name:     "decimal scale narrowing",
			existing: "decimal(10,2)",
			desired:  "decimal(12,1)",
		},
		{
			name:     "boolean storage is not numeric widening",
			existing: "tinyint(1)",
			desired:  "decimal(65,30)",
		},
		{
			name:     "text to varchar is not implicit widening",
			existing: "text",
			desired:  "varchar(255)",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if isAutoColumnTypeChangeSupported(tc.existing, tc.desired) {
				t.Fatalf("isAutoColumnTypeChangeSupported(%q, %q) = true, want false", tc.existing, tc.desired)
			}
		})
	}
}

func TestIsSafeAutoColumnTypeChangeAllowsJSONToBoundedText(t *testing.T) {
	for _, desired := range []string{"TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"} {
		if !isAutoColumnTypeChangeSupported("JSON", desired) {
			t.Fatalf("isAutoColumnTypeChangeSupported(JSON, %s) = false, want true", desired)
		}
	}
}

func TestIsSafeAutoColumnTypeChangeRejectsOtherJSONChanges(t *testing.T) {
	for _, desired := range []string{"VARCHAR(255)", "BLOB", "VARBINARY(255)"} {
		if isAutoColumnTypeChangeSupported("JSON", desired) {
			t.Fatalf("isAutoColumnTypeChangeSupported(JSON, %s) = true, want false", desired)
		}
	}
}

func TestIsSafeAutoColumnTypeChangeAllowsTemporalPrecisionWidening(t *testing.T) {
	cases := []struct {
		name     string
		existing string
		desired  string
	}{
		{name: "datetime default precision to microseconds", existing: "datetime", desired: "DATETIME(6)"},
		{name: "datetime milliseconds to microseconds", existing: "datetime(3)", desired: "datetime(6)"},
		{name: "timestamp default precision to microseconds", existing: "timestamp", desired: "timestamp(6)"},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if !isAutoColumnTypeChangeSupported(tc.existing, tc.desired) {
				t.Fatalf("isAutoColumnTypeChangeSupported(%q, %q) = false, want true", tc.existing, tc.desired)
			}
		})
	}
}

func TestIsSafeAutoColumnTypeChangeRejectsUnsafeTemporalChanges(t *testing.T) {
	cases := []struct {
		name     string
		existing string
		desired  string
	}{
		{name: "datetime precision narrowing", existing: "datetime(6)", desired: "datetime(3)"},
		{name: "datetime cannot become timestamp", existing: "datetime(6)", desired: "timestamp(6)"},
		{name: "date cannot become datetime", existing: "date", desired: "datetime(6)"},
		{name: "invalid precision", existing: "datetime(6)", desired: "datetime(7)"},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if isAutoColumnTypeChangeSupported(tc.existing, tc.desired) {
				t.Fatalf("isAutoColumnTypeChangeSupported(%q, %q) = true, want false", tc.existing, tc.desired)
			}
		})
	}
}
