package connector_outboundintent

import (
	"context"
	"testing"

	outboundintentv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/outboundintentv1"
)

type operationSetIntentSource struct {
	intent      outboundintentv1.Intent
	lastRequest outboundintentv1.ListRequest
	accepted    bool
}

func (s *operationSetIntentSource) ReadOutboundIntentGeneration(
	context.Context,
	outboundintentv1.GenerationRequest,
) (outboundintentv1.GenerationResponse, error) {
	return outboundintentv1.GenerationResponse{
		Generation: 1,
		Receipts:   operationSetReceipts(s.intent.CatalogRevision),
	}, nil
}

func (s *operationSetIntentSource) ListPendingOutboundIntents(
	_ context.Context,
	request outboundintentv1.ListRequest,
) (outboundintentv1.ListResponse, error) {
	s.lastRequest = request
	intents := []outboundintentv1.Intent(nil)
	if !s.accepted {
		intents = []outboundintentv1.Intent{s.intent}
	}
	return outboundintentv1.ListResponse{
		Intents:  intents,
		Receipts: operationSetReceipts(s.intent.CatalogRevision),
	}, nil
}

func (s *operationSetIntentSource) AcknowledgeOutboundIntent(
	_ context.Context,
	request outboundintentv1.AcknowledgeRequest,
) (outboundintentv1.AcknowledgeResponse, error) {
	s.accepted = true
	return outboundintentv1.AcknowledgeResponse{
		IntentID: request.IntentID,
		Outcome:  request.Outcome,
		Receipts: operationSetReceipts(request.CatalogRevision),
	}, nil
}

type operationSetIntentStore struct{}

func (*operationSetIntentStore) VerifySchema(context.Context) error { return nil }

func (*operationSetIntentStore) Accept(
	_ context.Context,
	scope Scope,
	intent outboundintentv1.Intent,
) (Command, bool, error) {
	return Command{
		CommandID: "operation-set-command",
		Scope:     scope,
		Intent:    intent,
		State:     StatePending,
	}, false, nil
}

func TestAcceptorNegotiatesCurrentOperationSetForMail(t *testing.T) {
	command := testMailCommand(t)
	source := &operationSetIntentSource{intent: command.Intent}
	acceptor := &Acceptor{
		source: source,
		store:  &operationSetIntentStore{},
		scope:  command.Scope,
	}

	if processed, err := acceptor.ProcessBatch(t.Context()); err != nil || processed != 1 {
		t.Fatalf("mail batch = (%d, %v), want (1, nil)", processed, err)
	}
	if source.lastRequest.MaxOperationSetVersion != outboundintentv1.CurrentOperationSetVersion {
		t.Fatalf(
			"mail operation set version = %d, want %d",
			source.lastRequest.MaxOperationSetVersion,
			outboundintentv1.CurrentOperationSetVersion,
		)
	}
}

func operationSetReceipts(revision uint64) outboundintentv1.Receipts {
	return outboundintentv1.Receipts{
		ProtocolVersion:   "1.0",
		CapabilityVersion: outboundintentv1.CapabilityName,
		CatalogRevision:   revision,
		SchemaGeneration:  7,
		EngineGeneration:  9,
		SecurityEpoch:     11,
	}
}
