package worker

import (
	"context"
	"encoding/json"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	query "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	mutation "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
)

func TestMutationAndStatusNeverSerializeRuntimeDiagnostics(t *testing.T) {
	values := []mutation.OperationResult{{Kind: mutation.OperationCreate, RecordID: "private-record", Errors: []mutation.OperationError{
		{Kind: mutation.ErrorInternal, AuthoredMessage: "private-internal-message", Fields: []string{"private-field"}},
		{Kind: mutation.ErrorAccessDenied, AuthoredMessage: "private-access-message", Fields: []string{"Name"}},
		{Kind: mutation.ErrorInvalidOperation, AuthoredMessage: "private-operation-message", CreateFromSourceGuard: &mutation.CreateFromSourceGuard{ObjectID: "private-object", ActionIDs: []string{"private-action"}}},
		{Kind: mutation.ErrorCustomValidation, AuthoredMessage: "A name is required.", Fields: []string{"Name"}},
		{Kind: mutation.ErrorPolicyDenied, AuthoredMessage: "The sales window is closed."},
		{Kind: mutation.ErrorKind("private-future-kind"), AuthoredMessage: "private-future-message"},
	}}}
	ports := Ports{
		Authorize: func(ctx context.Context, _ string, _ []string) (context.Context, error) { return ctx, nil },
		Query: func(context.Context, string, query.Request) (query.Response, error) {
			t.Fatal("unexpected query")
			return query.Response{}, nil
		},
		Mutate: func(context.Context, string, mutation.Request) (mutation.Response, error) {
			return mutation.Response{CommandID: "private-command", CommandDigest: "private-digest", Results: values}, nil
		},
		Status: func(context.Context, string, mutation.Request) (mutation.StatusResponse, error) {
			return mutation.StatusResponse{CommandID: "private-command", CommandDigest: "private-digest", State: mutation.CommandCompleted, Results: values}, nil
		},
	}
	w, err := New(Config{PublicOrigin: "https://crm.example", Version: "test", RequestTimeout: time.Second, Ports: ports})
	if err != nil {
		t.Fatal(err)
	}
	for _, name := range []string{"crm_mutate_record", "crm_mutation_status"} {
		t.Run(name, func(t *testing.T) {
			r := httptest.NewRequest("POST", "https://crm.example/mcp", strings.NewReader(`{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"`+name+`","arguments":{"operation":"CREATE","object":"Account","idempotency_key":"one","fields":{"Name":"Example"}}}}`))
			r.Header.Set("Authorization", "Bearer fixture-user")
			r.Header.Set("Content-Type", "application/json")
			r.Header.Set("Accept", "application/json, text/event-stream")
			out := httptest.NewRecorder()
			w.ServeHTTP(out, r)
			body := out.Body.String()
			if out.Code != 200 || !strings.Contains(body, `"isError":true`) {
				t.Fatalf("unexpected tool result: %s", body)
			}
			for _, forbidden := range []string{"private-", "authored_message", "create_from_source_guard", "command_id", "command_digest", "receipts"} {
				if strings.Contains(body, forbidden) {
					t.Fatalf("Runtime detail leaked: %s", forbidden)
				}
			}
			for _, wanted := range []string{"INTERNAL_ERROR", "ACCESS_DENIED", "Use the supported CRM action", "A name is required.", "The sales window is closed."} {
				if !strings.Contains(body, wanted) {
					t.Fatalf("missing public projection: %s", wanted)
				}
			}
		})
	}
}

func TestMutationSuccessAndPendingStatusProjection(t *testing.T) {
	created := true
	results, failed, err := projectMutationResults([]mutation.OperationResult{{Kind: mutation.OperationCreate, RecordID: "new-record", Success: true, Created: &created}})
	if err != nil || failed {
		t.Fatalf("success rejected: %v", err)
	}
	raw, err := json.Marshal(results)
	if err != nil || string(raw) != `[{"operation":"CREATE","success":true,"record_id":"new-record","created":true}]` {
		t.Fatalf("unexpected public success: %s %v", raw, err)
	}
	results, failed, err = projectMutationResults(nil)
	if err != nil || failed || results == nil || len(results) != 0 {
		t.Fatal("pending command acquired a false outcome")
	}
	if _, _, err := projectMutationResults([]mutation.OperationResult{{Kind: mutation.OperationUpsert, Success: true}}); err == nil {
		t.Fatal("unexpected operation was exposed")
	}
}
