package catalogsystem

import (
	"regexp"
	"strconv"
	"strings"
	"testing"

	"github.com/pingcap/tidb/pkg/parser"
	_ "github.com/pingcap/tidb/pkg/parser/test_driver"
)

func TestSchemaParsesWithTiDB(t *testing.T) {
	sqlParser := parser.New()
	for _, statement := range SchemaStatementsForTest() {
		if _, _, err := sqlParser.Parse(statement, "", ""); err != nil {
			t.Fatalf("system slot authority schema does not parse: %v\n%s", err, statement)
		}
	}
}

func TestSchemaOwnsExactlyFourGlobalSystemAuthorityTables(t *testing.T) {
	statements := SchemaStatementsForTest()
	if len(statements) != 4 {
		t.Fatalf("schema has %d statements, want exactly four tables", len(statements))
	}
	joined := strings.Join(statements, "\n")
	required := []string{
		"_System_CatalogSystemLayoutBundleSlot",
		"_System_CatalogSystemLayoutBundleSlotHistory",
		"_System_CatalogSystemLayoutBundleSlotCommand",
		"_System_CatalogSystemLayoutBundleSlotCommandOutcome",
		"SlotOwnerKind = 'system'",
		"SlotOwnerNamespace = 'io.nexuscrm.system'",
		"TransitionOrdinal = 1",
		"TransitionOrdinal = 2",
		"CommandId CHAR(36)",
		"PrincipalId",
		"PrincipalAuditDigest",
		"RequestDigest",
		"OutcomeDigest",
	}
	for _, value := range required {
		if !strings.Contains(joined, value) {
			t.Fatalf("system slot authority schema is missing %q", value)
		}
	}
	for _, value := range []string{
		"OrgId",
		"Tenant",
		"AppId",
		"Publication",
		"AuthorityEvidence",
		"VerificationReceipt",
		"LayoutBundleRevision",
		"ServingSelector",
		"DELETE FROM",
		"ON DELETE",
	} {
		if strings.Contains(joined, value) {
			t.Fatalf("system slot authority schema leaked forbidden vocabulary %q", value)
		}
	}
}

func TestOutcomeResultColumnFitsEveryClosedResult(t *testing.T) {
	joined := strings.Join(SchemaStatementsForTest(), "\n")
	match := regexp.MustCompile(`Result VARCHAR\(([0-9]+)\)`).FindStringSubmatch(joined)
	if len(match) != 2 {
		t.Fatal("outcome Result column has no fixed VARCHAR bound")
	}
	width, err := strconv.Atoi(match[1])
	if err != nil {
		t.Fatal(err)
	}
	for _, result := range []Result{
		ResultApplied,
		ResultExpectedPriorMismatch,
		ResultAuthorityStateConflict,
	} {
		if len(result) > width {
			t.Fatalf("Result column width %d cannot store %q", width, result)
		}
	}
}

func TestSchemaStatementsAreDefensive(t *testing.T) {
	first := SchemaStatementsForTest()
	first[0] = "changed"
	if SchemaStatementsForTest()[0] == "changed" {
		t.Fatal("SchemaStatementsForTest returned shared storage")
	}
}
