package controlplane

import (
	"context"
	"strings"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
)

func TestRequireConnectorPackDependencyInstallIDsConverged(t *testing.T) {
	for _, tc := range []struct {
		name    string
		count   int
		wantErr bool
	}{
		{name: "converged", count: 0},
		{name: "blank current dependency", count: 1, wantErr: true},
	} {
		t.Run(tc.name, func(t *testing.T) {
			db, mock, err := sqlmock.New()
			if err != nil {
				t.Fatalf("sqlmock.New: %v", err)
			}
			defer db.Close()

			mock.ExpectQuery(`(?s)SELECT COUNT\(\*\).*_System_ConnectorInboundRoute.*_System_ConnectorInboundHandlerConfig.*_System_ConnectorCalloutProfile`).
				WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(tc.count))

			err = requireConnectorPackDependencyInstallIDsConverged(context.Background(), db)
			if tc.wantErr {
				if err == nil || !strings.Contains(err.Error(), "run a full setup apply") {
					t.Fatalf("requireConnectorPackDependencyInstallIDsConverged error = %v, want full-apply prerequisite", err)
				}
			} else if err != nil {
				t.Fatalf("requireConnectorPackDependencyInstallIDsConverged: %v", err)
			}
			if err := mock.ExpectationsWereMet(); err != nil {
				t.Fatalf("sql expectations: %v", err)
			}
		})
	}
}

func TestDemoteStaleConnectorInboundRouteIncarnationsPreservesBacklogRows(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock.New: %v", err)
	}
	defer db.Close()

	mock.ExpectExec(`(?s)UPDATE _System_ConnectorInboundRoute r.*SET r.IsCurrent = 0.*r.InstalledPackId.*p.PackInstallId`).
		WillReturnResult(sqlmock.NewResult(0, 1))
	if err := demoteStaleConnectorInboundRouteIncarnations(context.Background(), db); err != nil {
		t.Fatalf("demoteStaleConnectorInboundRouteIncarnations: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
	if strings.Contains(demoteStaleConnectorInboundRouteIncarnationsSQL, "IsDeleted = 1") {
		t.Fatal("terminal recovery must demote stale live routing without deleting backlog authority")
	}
}

func TestConnectorPackDependencyInstallIDPreflightIgnoresBlankHistoricalChildrenWithCurrentIdentity(t *testing.T) {
	for _, fragment := range []string{
		"FROM _System_ConnectorInboundHandlerConfig active_child",
		"active_child.CapabilityKind = c.CapabilityKind",
		"FROM _System_ConnectorCalloutProfile active_child",
		"active_child.ProfileName = c.ProfileName",
		"active_child.InstalledPackId = p.PackInstallId",
	} {
		if !strings.Contains(connectorPackDependencyInstallIDPreflightSQL, fragment) {
			t.Fatalf("preflight SQL must ignore historical blank child rows when active identity exists; missing %q", fragment)
		}
	}
}

func TestConnectorPackDependencyInstallIDPreflightRejectsBlankActiveParent(t *testing.T) {
	if strings.Count(connectorPackDependencyInstallIDPreflightSQL, "COALESCE(p.PackInstallId, '') = ''") != 3 {
		t.Fatal("every connector dependency family must fail completed-marker startup when its active parent identity is blank")
	}
}

func TestConnectorPackDependencyInstallIDPreflightRejectsStaleCurrentRouteIdentity(t *testing.T) {
	if !strings.Contains(connectorPackDependencyInstallIDPreflightSQL, "r.InstalledPackId <> p.PackInstallId") {
		t.Fatal("completed-marker startup must reject a current route whose nonblank install identity is stale")
	}
}

func TestConnectorPackDependencyInstallIDPreflightRejectsStaleChildrenWithoutCurrentIdentity(t *testing.T) {
	for _, fragment := range []string{
		"FROM _System_ConnectorInboundHandlerConfig active_child",
		"FROM _System_ConnectorCalloutProfile active_child",
		"active_child.InstalledPackId = p.PackInstallId",
	} {
		if !strings.Contains(connectorPackDependencyInstallIDPreflightSQL, fragment) {
			t.Fatalf("completed-marker startup must require a current child identity; missing %q", fragment)
		}
	}
}
