package runtimeapi

import (
	"context"
	"testing"
	"time"

	"github.com/nexuscrm/backend/internal/runtimeassembly"
	"github.com/nexuscrm/persistence"
	"github.com/pingcap-inc/nexuscrm-api-host/runtimegrpc"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/applicationnavigationv1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/mapping"
)

type navigationProcessEngine struct {
	t     *testing.T
	calls int
}

func (e *navigationProcessEngine) check(c runtimeassembly.NavigationCaller) {
	e.t.Helper()
	if c.OwnerID != "test.application" || c.Actor.ID == "" || c.PermissionFloor.Validate() != nil {
		e.t.Fatalf("untrusted caller: %+v", c)
	}
	e.calls++
}
func (e *navigationProcessEngine) Read(_ context.Context, c runtimeassembly.NavigationCaller, r semantic.ReadRequest) (semantic.Document, error) {
	e.check(c)
	return semantic.Document{ApplicationID: r.ApplicationID, Revision: 1, Items: []semantic.Item{}}, nil
}
func (e *navigationProcessEngine) Resolve(_ context.Context, c runtimeassembly.NavigationCaller, r semantic.ResolveRequest) ([]semantic.Document, error) {
	e.check(c)
	return []semantic.Document{{ApplicationID: r.ApplicationIDs[0], Revision: 2, Items: []semantic.Item{}}}, nil
}
func (e *navigationProcessEngine) Save(_ context.Context, c runtimeassembly.NavigationCaller, r semantic.SaveRequest) (persistence.NavigationMutationResult, error) {
	e.check(c)
	return persistence.NavigationMutationResult{Document: semantic.Document{ApplicationID: r.ApplicationID, Revision: r.ExpectedRevision + 1, Items: r.Items}, Changed: true}, nil
}
func TestRuntimeNavigationUsesAuthenticatedAdmissionWithoutCatalog(t *testing.T) {
	fixture := newServingFixture(t, 17)
	admission, err := NewApplicationNavigationAdmission(ApplicationNavigationSelection{OrgID: testOrgID, AppInstallationID: testInstallationID, WorkloadID: testWorkloadID, FrontendAppID: "test.application"})
	if err != nil {
		t.Fatal(err)
	}
	engine := &navigationProcessEngine{t: t}
	connection := startPlatformCapabilityProcess(t, fixture, semantic.CapabilityName, runtimegrpc.ResourceClassHeavyWork, func(c *ProcessConfig) { c.ApplicationNavigation = engine; c.ApplicationNavigationAdmission = admission })
	ctx, cancel := context.WithTimeout(platformProtocolContext(context.Background(), semantic.CapabilityName), time.Second)
	defer cancel()
	client := runtimev1.NewApplicationNavigationServiceClient(connection)
	read := semantic.ReadRequest{ApplicationID: "app"}
	wire, err := mapping.ToWireNavigationReadRequest(ctx, read)
	if err != nil {
		t.Fatal(err)
	}
	reply, err := client.Read(ctx, wire)
	if err != nil {
		t.Fatal(err)
	}
	document, err := mapping.FromWireNavigationReadResponse(read, reply)
	if err != nil {
		t.Fatal(err)
	}
	if document.Receipts.CatalogRevision != 0 || document.Document.Revision != 1 {
		t.Fatalf("read=%+v", document)
	}
	save := semantic.SaveRequest{ApplicationID: "app", ExpectedRevision: 1, IdempotencyKey: "save", Items: []semantic.Item{}}
	saveWire, err := mapping.ToWireNavigationSaveRequest(ctx, save)
	if err != nil {
		t.Fatal(err)
	}
	saveReply, err := client.Save(ctx, saveWire)
	if err != nil {
		t.Fatal(err)
	}
	saved, err := mapping.FromWireNavigationSaveResponse(save, saveReply)
	if err != nil {
		t.Fatal(err)
	}
	if saved.Receipts.CatalogRevision != 0 || saved.Receipts.SecurityEpoch != document.Receipts.SecurityEpoch || saved.Document.Revision != 2 {
		t.Fatalf("saved=%+v", saved)
	}
	resolve := semantic.ResolveRequest{ApplicationIDs: []string{"app"}}
	resolveWire, err := mapping.ToWireNavigationResolveRequest(ctx, resolve)
	if err != nil {
		t.Fatal(err)
	}
	resolveReply, err := client.Resolve(ctx, resolveWire)
	if err != nil {
		t.Fatal(err)
	}
	resolved, err := mapping.FromWireNavigationResolveResponse(resolve, resolveReply)
	if err != nil {
		t.Fatal(err)
	}
	if len(resolved.Documents) != 1 || resolved.Documents[0].Items == nil || engine.calls != 3 {
		t.Fatalf("resolve=%+v calls=%d", resolved, engine.calls)
	}
}
