//go:build integration

package controlplane

import (
	"context"
	"database/sql"
	"testing"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/nexuscrm/kernel/pkg/schema"
	"github.com/pingcap-inc/nexuscrm-controlplane/bootstrapimpl"
)

func TestLayoutConfigJSONToTextSchemaUpgradePreservesRowsAndFutureNumericLexemes(t *testing.T) {
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	t.Cleanup(cleanup)

	rawDB, err := sql.Open("mysql", cfg.FormatDSN())
	if err != nil {
		t.Fatalf("open temporary TiDB: %v", err)
	}
	t.Cleanup(func() { _ = rawDB.Close() })

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
	t.Cleanup(cancel)
	if _, err := rawDB.ExecContext(ctx, `CREATE TABLE LayoutConfigMigration (
		Id VARCHAR(64) PRIMARY KEY,
		Config JSON NOT NULL
	)`); err != nil {
		t.Fatalf("create legacy JSON table: %v", err)
	}
	if _, err := rawDB.ExecContext(ctx, `INSERT INTO LayoutConfigMigration (Id, Config) VALUES (?, ?)`,
		"before", `{"amount":12.50,"large":9007199254740993}`); err != nil {
		t.Fatalf("insert legacy JSON row: %v", err)
	}

	var legacySerialization string
	if err := rawDB.QueryRowContext(ctx, `SELECT Config FROM LayoutConfigMigration WHERE Id = ?`, "before").Scan(&legacySerialization); err != nil {
		t.Fatalf("read legacy JSON serialization: %v", err)
	}

	if err := bootstrapimpl.ReconcileTableColumns(rawDB, []schema.TableDefinition{{
		TableName: "LayoutConfigMigration",
		Columns: []schema.ColumnDefinition{{
			Name:     "Config",
			Type:     "MEDIUMTEXT",
			Nullable: false,
		}},
	}}); err != nil {
		t.Fatalf("reconcile JSON to MEDIUMTEXT: %v", err)
	}

	var columnType string
	if err := rawDB.QueryRowContext(ctx, `SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'LayoutConfigMigration' AND COLUMN_NAME = 'Config'`).Scan(&columnType); err != nil {
		t.Fatalf("read migrated column type: %v", err)
	}
	if columnType != "mediumtext" {
		t.Fatalf("migrated column type = %q, want mediumtext", columnType)
	}

	var retainedSerialization string
	if err := rawDB.QueryRowContext(ctx, `SELECT Config FROM LayoutConfigMigration WHERE Id = ?`, "before").Scan(&retainedSerialization); err != nil {
		t.Fatalf("read retained row: %v", err)
	}
	if retainedSerialization != legacySerialization {
		t.Fatalf("retained JSON serialization changed during migration: before=%q after=%q", legacySerialization, retainedSerialization)
	}

	exact := `{"amount":12.50,"large":9007199254740993,"precise":0.123456789012345678901234567890}`
	if _, err := rawDB.ExecContext(ctx, `INSERT INTO LayoutConfigMigration (Id, Config) VALUES (?, ?)`, "after", exact); err != nil {
		t.Fatalf("insert exact post-migration JSON text: %v", err)
	}
	var storedExact string
	if err := rawDB.QueryRowContext(ctx, `SELECT Config FROM LayoutConfigMigration WHERE Id = ?`, "after").Scan(&storedExact); err != nil {
		t.Fatalf("read exact post-migration JSON text: %v", err)
	}
	if storedExact != exact {
		t.Fatalf("post-migration JSON text = %q, want byte-exact %q", storedExact, exact)
	}
}
