package serverruntime

import (
	"net/http"
	"strings"
	"testing"

	eventfeature "github.com/nexuscrm/events"
	"github.com/nexuscrm/shared/pkg/dialect"
	sharederrors "github.com/nexuscrm/shared/pkg/errors"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

type testProductDialect struct {
	name string
}

func (d testProductDialect) Name() string       { return d.name }
func (d testProductDialect) OwningPack() string { return "test-pack" }
func (d testProductDialect) BasePath() string   { return "/test" }
func (d testProductDialect) Versions() []string { return []string{"v1"} }
func (d testProductDialect) Manifest() []dialect.Route {
	return nil
}
func (d testProductDialect) ErrorProjector() dialect.Projector {
	return func(*dialect.Request, *sharederrors.DomainWireError) (int, any, bool) {
		return http.StatusBadRequest, map[string]any{"error": "projected"}, true
	}
}
func (d testProductDialect) InternalErrorProjector() dialect.InternalErrorProjector {
	return func(*dialect.Request) (int, any) {
		return http.StatusInternalServerError, map[string]any{"error": "internal"}
	}
}

func TestRegisterProductDistributionCapabilitiesAddsDialectHostPrimitive(t *testing.T) {
	const dialectName = "test-product-dialect-a2"

	_, err := RegisterProductDistributionCapabilities(NewProductDistribution(ProductHooks{
		OwningAppPacks: []string{"test-pack"},
		Dialects: func(DialectRegistrationContext) []dialect.Dialect {
			return []dialect.Dialect{testProductDialect{name: dialectName}}
		},
	}))
	if err != nil {
		t.Fatalf("RegisterProductDistributionCapabilities: %v", err)
	}

	registry := packs.DefaultHostPrimitiveRegistry()
	if !registry.Supports(packs.HostPrimitiveRequirement{
		Kind: packs.HostPrimitiveKindProductDialect,
		Name: dialectName,
	}) {
		t.Fatalf("distribution capabilities did not register product dialect host primitive %q", dialectName)
	}
}

func TestRegisterProductDistributionCapabilitiesAddsOfficialRepoSourceRevision(t *testing.T) {
	const packName = "test-official-pack-source-revision"
	const revision = "abc123"

	_, err := RegisterProductDistributionCapabilities(NewProductDistribution(ProductHooks{
		Capabilities: ProductCapabilities{
			OfficialRepoSourceRevisions: []OfficialRepoSourceRevision{
				{Name: packName, Revision: revision},
			},
		},
	}))
	if err != nil {
		t.Fatalf("RegisterProductDistributionCapabilities: %v", err)
	}

	revisions := packs.DefaultOfficialRepoSourceRevisions()
	if revisions[packName] != revision {
		t.Fatalf("DefaultOfficialRepoSourceRevisions()[%q] = %q, want %q", packName, revisions[packName], revision)
	}
}

func TestRegisterProductDistributionCapabilitiesAddsNoSubscriberRecordEventObjects(t *testing.T) {
	restore := eventfeature.ResetDefaultNoSubscriberRecordEventObjectsForTest()
	t.Cleanup(restore)

	_, err := RegisterProductDistributionCapabilities(NewProductDistribution(ProductHooks{
		Capabilities: ProductCapabilities{
			NoSubscriberRecordEventObjects: []string{"IssueWorklog"},
		},
	}))
	if err != nil {
		t.Fatalf("RegisterProductDistributionCapabilities: %v", err)
	}

	if got := eventfeature.DefaultNoSubscriberRecordEventObjects(); len(got) != 1 || got[0] != "IssueWorklog" {
		t.Fatalf("DefaultNoSubscriberRecordEventObjects() = %#v, want [IssueWorklog]", got)
	}
}

func TestComposeProductDistributionRejectsConflictingOfficialRepoSourceRevisions(t *testing.T) {
	_, err := ComposeProductDistribution(NewProductDistribution(
		ProductHooks{
			Capabilities: ProductCapabilities{
				OfficialRepoSourceRevisions: []OfficialRepoSourceRevision{
					{Name: "shared-pack", Revision: "rev-a"},
				},
			},
		},
		ProductHooks{
			Capabilities: ProductCapabilities{
				OfficialRepoSourceRevisions: []OfficialRepoSourceRevision{
					{Name: "shared-pack", Revision: "rev-b"},
				},
			},
		},
	))
	if err == nil {
		t.Fatal("ComposeProductDistribution accepted conflicting official_repo source revisions")
	}
	if got := err.Error(); !strings.Contains(got, "shared-pack") || !strings.Contains(got, "rev-b") || !strings.Contains(got, "rev-a") {
		t.Fatalf("ComposeProductDistribution error = %q, want conflicting revision details", got)
	}
}
