package sfcrmappservice

import (
	"context"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"github.com/pingcap-inc/nexuscrm-api-host/runtimegrpc"
	filessemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/filesv1"
	identitysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/identityv1"
	"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/credentials"
	"google.golang.org/grpc/metadata"
)

type recordFilesGRPCServer struct {
	runtimev1.UnimplementedIdentityContextServiceServer
	runtimev1.UnimplementedAuthorizedFilesServiceServer

	mu             sync.Mutex
	identityCalls  int
	createCalls    int
	receivedHeader filessemantic.CreateHeader
	receivedBody   []byte
}

func (server *recordFilesGRPCServer) Exchange(
	ctx context.Context,
	request *runtimev1.ExchangeRequest,
) (*runtimev1.ExchangeResponse, error) {
	if err := requireRecordFilesMetadata(ctx, true, false); err != nil {
		return nil, err
	}
	semanticRequest, err := mapping.FromWireIdentityExchangeRequest(ctx, request)
	if err != nil {
		return nil, mapping.ToIdentityStatusError(err)
	}
	if len(semanticRequest.RequestedCapabilities) != 1 ||
		semanticRequest.RequestedCapabilities[0] != filessemantic.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 *recordFilesGRPCServer) CreateFile(
	stream grpc.ClientStreamingServer[runtimev1.CreateFileRequest, runtimev1.CreateFileResponse],
) error {
	if err := requireRecordFilesMetadata(stream.Context(), false, true); err != nil {
		return err
	}
	state, err := filessemantic.NewCreateStreamState(stream.Context())
	if err != nil {
		return mapping.ToPlatformStatusError(err, filessemantic.CapabilityName)
	}
	var header filessemantic.CreateHeader
	var body []byte
	for {
		request, recvErr := stream.Recv()
		if errors.Is(recvErr, io.EOF) {
			if err := state.Complete(); err != nil {
				return mapping.ToPlatformStatusError(err, filessemantic.CapabilityName)
			}
			server.mu.Lock()
			server.createCalls++
			server.receivedHeader = header
			server.receivedBody = append([]byte(nil), body...)
			server.mu.Unlock()
			response, err := mapping.ToWireCreateFileResponse(filessemantic.CreateResponse{
				FileID: "grpc-file-1", FileName: header.FileName, Size: uint64(len(body)), ContentType: header.ContentType,
				Receipts: validFileReceipts(),
			})
			if err != nil {
				return err
			}
			return stream.SendAndClose(response)
		}
		if recvErr != nil {
			return recvErr
		}
		chunk, err := mapping.FromWireCreateFileChunk(request)
		if err != nil {
			return mapping.ToPlatformStatusError(err, filessemantic.CapabilityName)
		}
		if err := state.Observe(chunk); err != nil {
			return mapping.ToPlatformStatusError(err, filessemantic.CapabilityName)
		}
		if chunk.Header != nil {
			header = *chunk.Header
		} else {
			body = append(body, chunk.Data...)
		}
	}
}

func requireRecordFilesMetadata(ctx context.Context, wantBearer, wantDelegation 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 wantBearer != (len(bearer) == 1 && bearer[0] == "Bearer user-secret") {
		return errors.New("unexpected end-user authorization metadata")
	}
	delegation := values.Get(envelope.RuntimeDelegationMetadataKey)
	if wantDelegation != (len(delegation) == 1 && delegation[0] == "header.payload.signature") {
		return errors.New("unexpected Runtime delegation metadata")
	}
	return nil
}

func TestRecordFileUploadUsesProductionPlatformGRPCBoundary(t *testing.T) {
	target, caFile, server, cleanup := startRecordFilesGRPCServer(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 := newRecordFilesServiceWithPorts(
		t,
		func(ctx context.Context, bearer string, header filessemantic.CreateHeader) (RuntimeFileUpload, error) {
			return platform.BeginCreateFile(ctx, bearer, header)
		},
		func(ctx context.Context, bearer string, request filessemantic.OpenRequest) (RuntimeFileDownload, error) {
			return platform.OpenFile(ctx, bearer, request)
		},
		platform.DeleteFile,
	)
	request := recordFileUploadRequest(t, "/services/data/v63.0/record-files", "proof.txt", []byte("real-boundary"), map[string]string{
		fileUploadFieldParentID: "record-1", fileUploadFieldParentObjectAPIName: "Account",
	})
	recorder := httptest.NewRecorder()

	service.ServeHTTP(recorder, request)

	if recorder.Code != http.StatusCreated {
		t.Fatalf("status=%d body=%q", recorder.Code, recorder.Body.String())
	}
	server.mu.Lock()
	defer server.mu.Unlock()
	if server.identityCalls != 1 || server.createCalls != 1 ||
		server.receivedHeader.ParentObjectID != "Account" ||
		server.receivedHeader.ParentRecordID != "record-1" ||
		string(server.receivedBody) != "real-boundary" {
		t.Fatalf(
			"identity/create=%d/%d header=%+v body=%q",
			server.identityCalls,
			server.createCalls,
			server.receivedHeader,
			server.receivedBody,
		)
	}
}

func startRecordFilesGRPCServer(t *testing.T) (string, string, *recordFilesGRPCServer, 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 := &recordFilesGRPCServer{}
	runtimev1.RegisterIdentityContextServiceServer(grpcServer, implementation)
	runtimev1.RegisterAuthorizedFilesServiceServer(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()
	}
}

func recordFilesTestCredentials(t *testing.T) (credentials.TransportCredentials, []byte) {
	t.Helper()
	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		t.Fatal(err)
	}
	now := time.Now()
	template := &x509.Certificate{
		SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "runtime.test"},
		NotBefore: now.Add(-time.Minute), NotAfter: now.Add(time.Hour),
		KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		DNSNames: []string{"runtime.test"},
	}
	der, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
	if err != nil {
		t.Fatal(err)
	}
	keyDER, err := x509.MarshalPKCS8PrivateKey(key)
	if err != nil {
		t.Fatal(err)
	}
	certificatePEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
	keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
	certificate, err := tls.X509KeyPair(certificatePEM, keyPEM)
	if err != nil {
		t.Fatal(err)
	}
	return credentials.NewTLS(&tls.Config{
		MinVersion: tls.VersionTLS13, Certificates: []tls.Certificate{certificate},
	}), certificatePEM
}
