package catalogpublication

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"strings"

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

const (
	tidbCheckConstraintSettingQuery = `SELECT @@GLOBAL.tidb_enable_check_constraint`
	tidbEnableCheckConstraint       = `SET GLOBAL tidb_enable_check_constraint = ON`
)

// ensureTiDBCheckConstraintsEnabled makes the Catalog's CHECK-backed durable
// invariants effective before any Catalog DDL runs. TiDB otherwise accepts
// CHECK syntax while the feature is disabled but does not persist the
// constraint. MySQL has no TiDB-specific variable and already enforces CHECK
// constraints, so its exact unknown-variable response selects that path.
func ensureTiDBCheckConstraintsEnabled(ctx context.Context, db *sql.DB) error {
	enabled, isTiDB, err := readTiDBCheckConstraintSetting(ctx, db)
	if err != nil {
		return err
	}
	if !isTiDB || enabled {
		return nil
	}
	if _, err := db.ExecContext(ctx, tidbEnableCheckConstraint); err != nil {
		return fmt.Errorf("enable TiDB CHECK constraints for Catalog schema: %w", err)
	}
	enabled, isTiDB, err = readTiDBCheckConstraintSetting(ctx, db)
	if err != nil {
		return err
	}
	if !isTiDB || !enabled {
		return fmt.Errorf("enable TiDB CHECK constraints for Catalog schema: setting remains disabled")
	}
	return nil
}

func readTiDBCheckConstraintSetting(ctx context.Context, db *sql.DB) (bool, bool, error) {
	var raw string
	if err := db.QueryRowContext(ctx, tidbCheckConstraintSettingQuery).Scan(&raw); err != nil {
		var mysqlErr *mysql.MySQLError
		if errors.As(err, &mysqlErr) && mysqlErr.Number == 1193 {
			return false, false, nil
		}
		return false, false, fmt.Errorf("inspect TiDB CHECK constraint setting: %w", err)
	}
	switch strings.ToUpper(strings.TrimSpace(raw)) {
	case "ON", "1":
		return true, true, nil
	case "OFF", "0":
		return false, true, nil
	default:
		return false, true, fmt.Errorf("inspect TiDB CHECK constraint setting: unexpected value %q", raw)
	}
}
