package sfcrmappservice

import (
	"context"
	"errors"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"github.com/pingcap-inc/nexuscrm-api-host/runtimegrpc"
	identitysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/identityv1"
	metadataadminsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/metadataadminreadv1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/envelope"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/mapping"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

type metadataAdminReadGRPCServer struct {
	runtimev1.UnimplementedIdentityContextServiceServer
	runtimev1.UnimplementedMetadataAdminReadServiceServer

	mu            sync.Mutex
	identityCalls int
	indexCalls    int
	ruleCalls     int
}

func (server *metadataAdminReadGRPCServer) Exchange(
	ctx context.Context,
	wireRequest *runtimev1.ExchangeRequest,
) (*runtimev1.ExchangeResponse, error) {
	if err := requireMetadataAdminReadGRPCMetadata(ctx, true); err != nil {
		return nil, err
	}
	request, err := mapping.FromWireIdentityExchangeRequest(ctx, wireRequest)
	if err != nil {
		return nil, mapping.ToIdentityStatusError(err)
	}
	if len(request.RequestedCapabilities) != 1 ||
		request.RequestedCapabilities[0] != metadataadminsemantic.CapabilityName {
		return nil, errors.New("unexpected delegated capability")
	}
	server.mu.Lock()
	server.identityCalls++
	server.mu.Unlock()
	return mapping.ToWireIdentityExchangeResponse(identitysemantic.Response{
		OpaqueDelegation:    "header.payload.signature",
		ExpiresAtUnixSecond: time.Now().Add(time.Minute).Unix(),
	})
}

func (server *metadataAdminReadGRPCServer) ReadObjectAdminIndex(
	ctx context.Context,
	wireRequest *runtimev1.ReadObjectAdminIndexRequest,
) (*runtimev1.ReadObjectAdminIndexResponse, error) {
	if err := requireMetadataAdminReadGRPCMetadata(ctx, false); err != nil {
		return nil, err
	}
	request, err := mapping.FromWireReadObjectAdminIndexRequest(ctx, wireRequest)
	if err != nil {
		return nil, mapping.ToPlatformStatusError(err, metadataadminsemantic.CapabilityName)
	}
	description := "Customer accounts"
	server.mu.Lock()
	server.indexCalls++
	server.mu.Unlock()
	return mapping.ToWireReadObjectAdminIndexResponse(request, metadataadminsemantic.ObjectAdminIndexResponse{
		Objects: []metadataadminsemantic.ObjectAdminMetadata{{
			ObjectID: "Account", Description: &description, DeleteMode: "soft",
		}},
		Receipts: metadataAdminReadTestReceipts(17, 3),
	})
}

func (server *metadataAdminReadGRPCServer) ReadValidationRuleAdminIndex(
	ctx context.Context,
	wireRequest *runtimev1.ReadValidationRuleAdminIndexRequest,
) (*runtimev1.ReadValidationRuleAdminIndexResponse, error) {
	if err := requireMetadataAdminReadGRPCMetadata(ctx, false); err != nil {
		return nil, err
	}
	request, err := mapping.FromWireReadValidationRuleAdminIndexRequest(ctx, wireRequest)
	if err != nil {
		return nil, mapping.ToPlatformStatusError(err, metadataadminsemantic.CapabilityName)
	}
	server.mu.Lock()
	server.ruleCalls++
	server.mu.Unlock()
	return mapping.ToWireReadValidationRuleAdminIndexResponse(request, metadataadminsemantic.ValidationRuleAdminIndexResponse{
		ObjectID: request.ObjectID,
		Rules: []metadataadminsemantic.ValidationRuleMetadata{{
			RuleID: "rule-a", ObjectID: request.ObjectID, Name: "PositiveAmount", Active: true,
			Condition: "Amount < 0", ErrorMessage: "Amount must be positive",
		}},
		Receipts: metadataAdminReadTestReceipts(17, 3),
	})
}

func requireMetadataAdminReadGRPCMetadata(ctx context.Context, identity bool) error {
	values, _ := metadata.FromIncomingContext(ctx)
	if got := values.Get("authorization"); len(got) != 1 || got[0] != "Bearer workload-secret" {
		return errors.New("missing workload authorization")
	}
	bearer := values.Get(runtimegrpc.EndUserAuthorizationMetadataKey)
	if identity != (len(bearer) == 1 && bearer[0] == "Bearer user-secret") {
		return errors.New("unexpected end-user authorization metadata")
	}
	delegation := values.Get(envelope.RuntimeDelegationMetadataKey)
	if identity == (len(delegation) == 1 && delegation[0] == "header.payload.signature") {
		return errors.New("unexpected Runtime delegation metadata")
	}
	return nil
}

func TestMetadataAdminReadUsesProductionPlatformGRPCBoundary(t *testing.T) {
	target, caFile, server, cleanup := startMetadataAdminReadGRPCServer(t)
	defer cleanup()
	startupCtx, cancelStartup := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancelStartup()
	platform, err := runtimegrpc.DialPlatformRuntime(startupCtx, runtimegrpc.RuntimeClientConfig{
		Target: target, AppInstallationID: "01900000-0000-7000-8000-000000000001",
		WorkloadToken: "workload-secret", CAFile: caFile, ServerName: "runtime.test",
		AttemptTimeout: time.Second,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer platform.Close()
	service := metadataAdminReadService(
		t, platform.ReadObjectAdminIndex,
		platform.ReadValidationRuleAdminIndex,
	)
	for _, path := range []string{
		"/services/data/v63.0/metadata/objects",
		"/services/data/v63.0/metadata/validation-rules?objectApiName=Opportunity",
	} {
		request := httptest.NewRequest(http.MethodGet, path, nil)
		request.Header.Set("Authorization", "Bearer user-secret")
		response := httptest.NewRecorder()
		service.ServeHTTP(response, request)
		if response.Code != http.StatusOK {
			t.Fatalf("%s status=%d body=%s", path, response.Code, response.Body.String())
		}
	}
	server.mu.Lock()
	defer server.mu.Unlock()
	if server.identityCalls != 1 || server.indexCalls != 1 ||
		server.ruleCalls != 1 {
		t.Fatalf("gRPC identity/index/rules calls = %d/%d/%d",
			server.identityCalls, server.indexCalls, server.ruleCalls)
	}
}

func startMetadataAdminReadGRPCServer(
	t *testing.T,
) (string, string, *metadataAdminReadGRPCServer, func()) {
	t.Helper()
	serverCredentials, caPEM := recordFilesTestCredentials(t)
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	grpcServer := grpc.NewServer(grpc.Creds(serverCredentials))
	implementation := &metadataAdminReadGRPCServer{}
	runtimev1.RegisterIdentityContextServiceServer(grpcServer, implementation)
	runtimev1.RegisterMetadataAdminReadServiceServer(grpcServer, implementation)
	go func() { _ = grpcServer.Serve(listener) }()
	caFile := filepath.Join(t.TempDir(), "runtime-ca.pem")
	if err := os.WriteFile(caFile, caPEM, 0o600); err != nil {
		t.Fatal(err)
	}
	return "passthrough:///" + listener.Addr().String(), caFile, implementation, func() {
		grpcServer.GracefulStop()
		_ = listener.Close()
	}
}
