package mapping_test

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"

	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/envelope"
	commonv1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/common/v1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/mapping"
	"google.golang.org/protobuf/proto"
)

func TestIdentifierAndFieldCountBoundariesThroughGeneratedCodec(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	exact := maximumRequest()
	if _, err := codecRequest(ctx, rawWireRequest(exact)); err != nil {
		t.Fatalf("exact identifier/count codec vector = %v", err)
	}
	tests := []struct {
		name   string
		mutate func(*semantic.Request)
		limit  semantic.LimitKind
	}{
		{name: "object", mutate: func(r *semantic.Request) { r.ObjectID += "X" }, limit: semantic.LimitObjectID},
		{name: "record", mutate: func(r *semantic.Request) { r.RecordID += "X" }, limit: semantic.LimitRecordID},
		{name: "field", mutate: func(r *semantic.Request) { r.SelectedRootFields[0] += "X" }, limit: semantic.LimitFieldID},
		{name: "field count", mutate: func(r *semantic.Request) { r.SelectedRootFields = append(r.SelectedRootFields, "OneOver") }, limit: semantic.LimitSelectedFields},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			request := exact
			request.SelectedRootFields = append([]string(nil), exact.SelectedRootFields...)
			tc.mutate(&request)
			_, err := codecRequest(ctx, rawWireRequest(request))
			var failure *semantic.Failure
			if !errors.As(err, &failure) || failure.LimitKind != tc.limit {
				t.Fatalf("one-over codec vector = %#v, want %s", err, tc.limit)
			}
		})
	}
}

type envelopeGolden struct {
	Schema   string `json:"schema"`
	Semantic struct {
		LargestValidRequest                int    `json:"largest_valid_request_bytes"`
		RequestExact                       int    `json:"request_exact_bytes"`
		RequestOneOver                     int    `json:"request_one_over_bytes"`
		RequestOuterCapActiveValidBoundary bool   `json:"request_outer_cap_active_valid_boundary"`
		RequestVectorClassification        string `json:"request_vector_classification"`
		ResponseExact                      int    `json:"response_exact_bytes"`
		ResponseOneOver                    int    `json:"response_one_over_bytes"`
	} `json:"semantic"`
	Wire struct {
		LargestValidRequest int `json:"largest_valid_request_bytes"`
		RequestExact        int `json:"request_exact_bytes"`
		RequestOneOver      int `json:"request_one_over_bytes"`
		ResponseExact       int `json:"response_exact_bytes"`
		ResponseOneOver     int `json:"response_one_over_bytes"`
	} `json:"wire"`
	Transport struct {
		GRPCFrameHeaderBytes     int    `json:"grpc_frame_header_bytes"`
		RequestExactFramedBytes  int    `json:"request_exact_framed_bytes"`
		ResponseExactFramedBytes int    `json:"response_exact_framed_bytes"`
		ReceiveCap               int    `json:"receive_cap_bytes"`
		ReceiveMessageHeadroom   int    `json:"receive_message_headroom_bytes"`
		SendCap                  int    `json:"send_cap_bytes"`
		SendMessageHeadroom      int    `json:"send_message_headroom_bytes"`
		Decision                 string `json:"decision"`
	} `json:"transport"`
}

func TestApprovedSemanticEnvelopeThroughGeneratedCodec(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	largest := maximumRequest()
	wireLargest, err := mapping.ToWireRequest(ctx, largest)
	if err != nil {
		t.Fatalf("largest valid request: %v", err)
	}
	requestExact := requestOfSemanticSize(t, semantic.MaxSemanticRequestBytes)
	requestOneOver := requestOfSemanticSize(t, semantic.MaxSemanticRequestBytes+1)
	wireRequestExact := rawWireRequest(requestExact)
	wireRequestOneOver := rawWireRequest(requestOneOver)
	if _, err := codecRequest(ctx, wireRequestExact); err == nil {
		t.Fatal("semantic request exact adversarial vector unexpectedly passed independent identifier limits")
	}
	if _, err := codecRequest(ctx, wireRequestOneOver); err == nil {
		t.Fatal("semantic request one-over adversarial vector unexpectedly passed independent identifier limits")
	}

	responseExact := responseOfSemanticSize(t, semantic.MaxSemanticResponseBytes)
	wireResponseExact, err := mapping.ToWireResponse(responseExact)
	if err != nil {
		t.Fatalf("exact response: %v", err)
	}
	responseOneOver := responseOfSemanticSize(t, semantic.MaxSemanticResponseBytes+1)
	var failure *semantic.Failure
	if _, err := mapping.ToWireResponse(responseOneOver); !errors.As(err, &failure) || failure.LimitKind != semantic.LimitSemanticResponse {
		t.Fatalf("one-over response = %#v", err)
	}
	wireResponseOneOver := rawWireResponse(responseOneOver)
	encodedOneOver, err := proto.Marshal(wireResponseOneOver)
	if err != nil {
		t.Fatal(err)
	}
	var decodedOneOver runtimev1.ReadSelectedRootResponse
	if err := proto.Unmarshal(encodedOneOver, &decodedOneOver); err != nil {
		t.Fatal(err)
	}
	if _, err := mapping.FromWireResponse(&decodedOneOver); !errors.As(err, &failure) || failure.LimitKind != semantic.LimitSemanticResponse {
		t.Fatalf("decoded one-over response = %#v", err)
	}

	var got envelopeGolden
	got.Schema = "selected-root-wire-envelope.v1"
	got.Semantic.LargestValidRequest, _ = semantic.SemanticRequestSize(largest)
	got.Semantic.RequestExact, _ = semantic.SemanticRequestSize(requestExact)
	got.Semantic.RequestOneOver, _ = semantic.SemanticRequestSize(requestOneOver)
	got.Semantic.RequestOuterCapActiveValidBoundary = false
	got.Semantic.RequestVectorClassification = "adversarial outer-cap codec vectors; independent 64-byte field limits reject them before Runtime work"
	got.Semantic.ResponseExact, _ = semantic.SemanticResponseSize(responseExact)
	got.Semantic.ResponseOneOver, _ = semantic.SemanticResponseSize(responseOneOver)
	got.Wire.LargestValidRequest = proto.Size(wireLargest)
	got.Wire.RequestExact = proto.Size(wireRequestExact)
	got.Wire.RequestOneOver = proto.Size(wireRequestOneOver)
	got.Wire.ResponseExact = proto.Size(wireResponseExact)
	got.Wire.ResponseOneOver = proto.Size(wireResponseOneOver)
	got.Transport.GRPCFrameHeaderBytes = 5
	got.Transport.RequestExactFramedBytes = got.Wire.RequestExact + got.Transport.GRPCFrameHeaderBytes
	got.Transport.ResponseExactFramedBytes = got.Wire.ResponseExact + got.Transport.GRPCFrameHeaderBytes
	got.Transport.ReceiveCap = envelope.MaxRequestWireBytes
	got.Transport.ReceiveMessageHeadroom = envelope.MaxRequestWireBytes - got.Wire.RequestExact
	got.Transport.SendCap = envelope.MaxResponseWireBytes
	got.Transport.SendMessageHeadroom = envelope.MaxResponseWireBytes - got.Wire.ResponseExact
	got.Transport.Decision = "APPROVED: one conventional 4 MiB private unary envelope; capability semantic validation remains authoritative and gross transport oversize is rejected by gRPC"

	data, err := os.ReadFile("../testdata/codec_envelope_golden.json")
	if err != nil {
		t.Fatal(err)
	}
	var want envelopeGolden
	if err := json.Unmarshal(data, &want); err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(got, want) {
		encoded, _ := json.MarshalIndent(got, "", "  ")
		t.Fatalf("codec envelope changed; review deliberately:\n%s", encoded)
	}
}

func maximumRequest() semantic.Request {
	fields := make([]string, semantic.MaxSelectedFields)
	for i := range fields {
		prefix := fmt.Sprintf("F%06d", i)
		fields[i] = prefix + strings.Repeat("X", semantic.MaxFieldIdentifierBytes-len(prefix))
	}
	revision := ^uint64(0)
	return semantic.Request{
		ObjectID:           strings.Repeat("O", semantic.MaxObjectIdentifierBytes),
		RecordID:           strings.Repeat("r", semantic.MaxRecordIdentifierBytes),
		SelectedRootFields: fields,
		MinCatalogRevision: &revision,
	}
}

func requestOfSemanticSize(t *testing.T, target int) semantic.Request {
	t.Helper()
	request := maximumRequest()
	base, _ := semantic.SemanticRequestSize(request)
	request.SelectedRootFields[len(request.SelectedRootFields)-1] += strings.Repeat("X", target-base)
	if got, _ := semantic.SemanticRequestSize(request); got != target {
		t.Fatalf("request semantic bytes = %d, want %d", got, target)
	}
	return request
}

func responseOfSemanticSize(t *testing.T, target int) semantic.Response {
	t.Helper()
	value := "v"
	response := semantic.Response{
		RecordID: strings.Repeat("r", semantic.MaxRecordIdentifierBytes),
		Receipts: semantic.Receipts{
			ProtocolVersion: "1.0", CatalogRevision: ^uint64(0), SchemaGeneration: ^uint64(0),
			EngineGeneration: ^uint64(0), SecurityEpoch: ^uint64(0), CapabilityVersion: semantic.CapabilityName,
		},
	}
	for _, name := range maximumRequest().SelectedRootFields {
		fieldValue := value
		response.Fields = append(response.Fields, semantic.Field{Name: name, Kind: semantic.ValueKindString, String: &fieldValue})
	}
	base, _ := semantic.SemanticResponseSize(response)
	*response.Fields[len(response.Fields)-1].String += strings.Repeat("x", target-base)
	if got, _ := semantic.SemanticResponseSize(response); got != target {
		t.Fatalf("response semantic bytes = %d, want %d", got, target)
	}
	return response
}

func rawWireRequest(request semantic.Request) proto.Message {
	return &runtimev1.ReadSelectedRootRequest{
		ObjectId:           request.ObjectID,
		RecordId:           request.RecordID,
		SelectedRootFields: append([]string(nil), request.SelectedRootFields...),
		MinCatalogRevision: request.MinCatalogRevision,
	}
}

func rawWireResponse(response semantic.Response) proto.Message {
	// These helpers bypass semantic validation only so the approved one-over
	// vectors can be measured through the real generated codec.
	wire := &runtimev1.ReadSelectedRootResponse{
		RecordId: response.RecordID,
		Receipts: &commonv1.ConsistencyReceipts{
			ProtocolVersion:   &commonv1.ProtocolVersion{Major: 1},
			CatalogRevision:   response.Receipts.CatalogRevision,
			SchemaGeneration:  response.Receipts.SchemaGeneration,
			EngineGeneration:  response.Receipts.EngineGeneration,
			SecurityEpoch:     response.Receipts.SecurityEpoch,
			CapabilityVersion: &commonv1.CapabilityVersion{Name: semantic.CapabilityName, Major: 1},
		},
	}
	for _, field := range response.Fields {
		wire.Fields = append(wire.Fields, &runtimev1.SelectedRootField{
			Name:         field.Name,
			DeclaredKind: runtimev1.ValueKind_VALUE_KIND_STRING,
			Value:        &runtimev1.SelectedRootField_StringValue{StringValue: *field.String},
		})
	}
	return wire
}

func codecRequest(ctx context.Context, message proto.Message) (semantic.Request, error) {
	encoded, err := proto.Marshal(message)
	if err != nil {
		return semantic.Request{}, err
	}
	var decoded runtimev1.ReadSelectedRootRequest
	if err := proto.Unmarshal(encoded, &decoded); err != nil {
		return semantic.Request{}, err
	}
	return mapping.FromWireRequest(ctx, &decoded)
}
