package dialectsfcrm

import (
	"context"
	"strings"
	"testing"
	"time"

	"github.com/nexuscrm/dialect-sf-crm/wire"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/dialect"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestConnectorSyncStatusMissingParamsUsesV63RequiredField(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), &dialect.Request{
		User:  testUser(),
		Query: map[string][]string{"object": {"Account"}},
	}, connectorSyncStatusDeps(&fakeConnectorSyncStatus{}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	assertSFError(t, resp, 400, wire.SFCodeRequiredFieldMissing)
}

func TestConnectorSyncStatusMissingUserUsesInvalidSession(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), &dialect.Request{
		Query: map[string][]string{"object": {"Account"}, "recordId": {"001"}},
	}, connectorSyncStatusDeps(&fakeConnectorSyncStatus{}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	assertSFError(t, resp, 401, wire.SFCodeInvalidSessionID)
}

func TestConnectorSyncStatusForbiddenUsesV63Envelope(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), connectorSyncStatusRequest(), connectorSyncStatusDeps(&fakeConnectorSyncStatus{
		err: &contract.ConnectorSyncStatusError{
			Kind:    contract.ConnectorSyncStatusErrorForbidden,
			Message: "Insufficient privileges to access connector sync status",
		},
	}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	assertSFError(t, resp, 403, wire.SFCodeForbidden)
}

func TestConnectorSyncStatusNotFoundMasksReadErrors(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), connectorSyncStatusRequest(), connectorSyncStatusDeps(&fakeConnectorSyncStatus{
		err: &contract.ConnectorSyncStatusError{
			Kind:    contract.ConnectorSyncStatusErrorNotFound,
			Message: "The requested resource does not exist",
		},
	}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	assertSFError(t, resp, 404, wire.SFCodeNotFound)
}

func TestConnectorSyncStatusInternalIsSanitized(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), connectorSyncStatusRequest(), connectorSyncStatusDeps(&fakeConnectorSyncStatus{
		err: &contract.ConnectorSyncStatusError{
			Kind:    contract.ConnectorSyncStatusErrorInternal,
			Message: "An internal server error occurred. Contact your system administrator.",
		},
	}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	assertSFError(t, resp, 500, wire.SFCodeInternalError)
	body := marshalJSON(t, resp.Body)
	if strings.Contains(body, "driver leaked detail") {
		t.Fatalf("internal detail leaked: %s", body)
	}
}

func TestConnectorSyncStatusProjectsOnlyAllowedFields(t *testing.T) {
	linkStatus := "finalized"
	attemptStatus := "terminal_failed"
	var statusCode int64 = 422
	lastErr := time.Date(2026, 1, 1, 0, 0, 1, 2*1e6, time.FixedZone("CET", 3600))
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), connectorSyncStatusRequest(), connectorSyncStatusDeps(&fakeConnectorSyncStatus{
		result: &contract.ConnectorSyncStatusResult{
			Object:   "Account",
			RecordID: "001",
			SyncStatuses: []contract.ConnectorSyncStatusRow{{
				ConnectorOwnerKey:  "hubspot-crm",
				ActionType:         "PushToConnector",
				DestinationSlotID:  "hubspot-company",
				TargetObject:       "companies",
				LinkStatus:         &linkStatus,
				LastAttemptStatus:  &attemptStatus,
				ResponseStatusCode: &statusCode,
				LastErrorAt:        &lastErr,
			}},
		},
	}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	if resp.Status != 200 {
		t.Fatalf("status = %d, want 200", resp.Status)
	}
	body := marshalJSON(t, resp.Body)
	for _, key := range []string{
		`"connectorOwnerKey"`,
		`"actionType"`,
		`"destinationSlotId"`,
		`"targetObject"`,
		`"linkStatus"`,
		`"lastAttemptStatus"`,
		`"responseStatusCode"`,
		`"lastErrorAt":"2025-12-31T23:00:01.002Z"`,
	} {
		if !strings.Contains(body, key) {
			t.Fatalf("body missing %s: %s", key, body)
		}
	}
	for _, forbidden := range []string{
		"actionSlotId",
		"linkKey",
		"linkRemoteId",
		"connectorNamespace",
		"lastError\"",
		"supersededByAttemptId",
		`"id":`,
	} {
		if strings.Contains(body, forbidden) {
			t.Fatalf("body leaked %s: %s", forbidden, body)
		}
	}
}

func TestConnectorSyncStatusEmptyResultUsesEmptyArray(t *testing.T) {
	resp, err := AdminConnectorSyncStatusNeutralHandler(context.Background(), connectorSyncStatusRequest(), connectorSyncStatusDeps(&fakeConnectorSyncStatus{
		result: &contract.ConnectorSyncStatusResult{Object: "Account", RecordID: "001"},
	}))
	if err != nil {
		t.Fatalf("handler returned error: %v", err)
	}
	body := marshalJSON(t, resp.Body)
	if !strings.Contains(body, `"syncStatuses":[]`) {
		t.Fatalf("syncStatuses should be empty array, got %s", body)
	}
}

func connectorSyncStatusRequest() *dialect.Request {
	return &dialect.Request{
		User:  testUser(),
		Query: map[string][]string{"object": {"Account"}, "recordId": {"001"}},
	}
}

func connectorSyncStatusDeps(syncStatus contract.ConnectorSyncStatus) dialect.Deps {
	return dialect.Deps{Contracts: contract.Deps{ConnectorSyncStatus: syncStatus}}
}

type fakeConnectorSyncStatus struct {
	result *contract.ConnectorSyncStatusResult
	err    error
}

func (f *fakeConnectorSyncStatus) GetConnectorSyncStatus(context.Context, *models.UserSession, string, string) (*contract.ConnectorSyncStatusResult, error) {
	if f.err != nil {
		return nil, f.err
	}
	return f.result, nil
}
