package exec

// mutationReceiptBatchSelector describes one request/output array whose exact
// order is part of the receipt identity. The identifier key is the name stored
// in the compact receipt, while sourceKey/elementKey name the validated JSON
// request or response shape.
type mutationReceiptBatchSelector struct {
	sourceKey     string
	identifierKey string
	elementKey    string
}

type mutationReceiptOutputScalar struct {
	identifierKey string
	keys          []string
	containers    []string
}

type mutationReceiptSelectorSpec struct {
	requiredInputScalars  []string
	optionalInputScalars  []string
	inputBatches          []mutationReceiptBatchSelector
	outputScalars         []mutationReceiptOutputScalar
	outputBatches         []mutationReceiptBatchSelector
	requireOutputSelector bool
}

func (spec mutationReceiptSelectorSpec) allowedOutputIdentifiers() map[string]struct{} {
	allowed := make(map[string]struct{}, len(spec.outputScalars)+len(spec.outputBatches))
	for _, selector := range spec.outputScalars {
		allowed[selector.identifierKey] = struct{}{}
	}
	for _, selector := range spec.outputBatches {
		allowed[selector.identifierKey] = struct{}{}
	}
	return allowed
}

func mutationReceiptSelectorSpecFor(domain, action string) (mutationReceiptSelectorSpec, bool) {
	var spec mutationReceiptSelectorSpec
	if domain == "workflow" {
		return workflowReceiptSelectorSpec(action)
	}
	if domain == "scheduled-message" {
		return scheduledMessageReceiptSelectorSpec(action)
	}
	switch domain {
	case "agent":
		switch action {
		case "create":
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
			spec.requireOutputSelector = true
		case "start", "stop", "restart":
			spec.requiredInputScalars = []string{"agentId"}
		case "update":
			spec.requiredInputScalars = []string{"agentId"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
		case "delete":
			spec.inputBatches = []mutationReceiptBatchSelector{{sourceKey: "agentIds", identifierKey: "agentIds"}}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
		case "duplicate":
			spec.requiredInputScalars = []string{"sourceAgentId"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "team":
		if action != "update" {
			return mutationReceiptSelectorSpec{}, false
		}
		spec.requiredInputScalars = []string{"teamId"}
	case "channel":
		switch action {
		case "create":
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "channelId", keys: []string{"channelId", "id"}, containers: []string{"channel"}}}
			spec.requireOutputSelector = true
		case "update":
			spec.requiredInputScalars = []string{"channelId"}
		case "agent-add", "agent-remove":
			spec.requiredInputScalars = []string{"channelId"}
			spec.inputBatches = []mutationReceiptBatchSelector{{sourceKey: "agents", identifierKey: "agentIds", elementKey: "agentId"}}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "channelId", keys: []string{"channelId"}}}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "project":
		switch action {
		case "create":
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "id", keys: []string{"id"}, containers: []string{"project"}}}
			spec.requireOutputSelector = true
		case "delete":
			spec.requiredInputScalars = []string{"id"}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "review":
		switch action {
		case "add":
			spec.optionalInputScalars = []string{"thread"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "contextId", keys: []string{"contextId", "id"}, containers: []string{"context"}}}
		case "delete":
			spec.requiredInputScalars = []string{"contextId"}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "role":
		switch action {
		case "create":
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
			spec.requireOutputSelector = true
		case "update", "delete", "apply":
			spec.requiredInputScalars = []string{"roleId"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "skill":
		switch action {
		case "create":
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "skillId", keys: []string{"skillId", "id"}, containers: []string{"skill"}}}
			spec.requireOutputSelector = true
		case "update", "import":
			spec.requiredInputScalars = []string{"skillId"}
		case "delete":
			spec.requiredInputScalars = []string{"skillId"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "approvalId", keys: []string{"approvalId"}}}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	case "profile":
		if action != "set-avatar" {
			return mutationReceiptSelectorSpec{}, false
		}
	case "task":
		switch action {
		case "create":
			spec.optionalInputScalars = []string{"channel"}
			spec.outputScalars = []mutationReceiptOutputScalar{{identifierKey: "channel", keys: []string{"channelRef"}}}
			spec.outputBatches = []mutationReceiptBatchSelector{{sourceKey: "tasks", identifierKey: "taskNumbers", elementKey: "taskNumber"}}
			spec.requireOutputSelector = true
		case "update", "checkpoint", "delete":
			spec.requiredInputScalars = []string{"channel", "number"}
		case "claim", "unclaim":
			spec.requiredInputScalars = []string{"channel"}
			spec.inputBatches = []mutationReceiptBatchSelector{{sourceKey: "numbers", identifierKey: "numbers"}}
		default:
			return mutationReceiptSelectorSpec{}, false
		}
	default:
		return mutationReceiptSelectorSpec{}, false
	}
	return addMutationReceiptIdentityFields(spec), true
}

// Workflow's four registered Exec actions carry their operation discriminator
// inside the request. The returned spec is intentionally based on that exact
// action, not on a verb suffix or on whatever identifiers happened to appear in
// the response.
func scheduledMessageReceiptSelectorSpec(action string) (mutationReceiptSelectorSpec, bool) {
	switch action {
	case "create":
		return addMutationReceiptIdentityFields(mutationReceiptSelectorSpec{
			outputScalars: []mutationReceiptOutputScalar{{identifierKey: "id", keys: []string{"id"}}}, requireOutputSelector: true,
		}), true
	case "update", "pause", "resume", "delete":
		return addMutationReceiptIdentityFields(mutationReceiptSelectorSpec{requiredInputScalars: []string{"id"}}), true
	default:
		return mutationReceiptSelectorSpec{}, false
	}
}

func workflowReceiptSelectorSpec(action string) (mutationReceiptSelectorSpec, bool) {
	switch action {
	case "plan":
		return workflowPlanReceiptSelectorSpec(), true
	case "trigger":
		return workflowTriggerReceiptSelectorSpec(), true
	case "run":
		return workflowRunReceiptSelectorSpec(), true
	case "step":
		return workflowStepMutationSelectorSpec(), true
	default:
		return mutationReceiptSelectorSpec{}, false
	}
}

func workflowPlanReceiptSelectorSpec() mutationReceiptSelectorSpec {
	return mutationReceiptSelectorSpec{outputScalars: []mutationReceiptOutputScalar{{identifierKey: "planId", keys: []string{"planId", "id"}, containers: []string{"plan", "draft"}}}}
}

func workflowTriggerReceiptSelectorSpec() mutationReceiptSelectorSpec {
	return mutationReceiptSelectorSpec{outputScalars: []mutationReceiptOutputScalar{{identifierKey: "triggerId", keys: []string{"triggerId", "id"}, containers: []string{"trigger"}}}}
}

func workflowRunReceiptSelectorSpec() mutationReceiptSelectorSpec {
	return mutationReceiptSelectorSpec{outputScalars: []mutationReceiptOutputScalar{{identifierKey: "runId", keys: []string{"runId", "id"}, containers: []string{"run"}}}}
}

func workflowStepMutationSelectorSpec() mutationReceiptSelectorSpec {
	return mutationReceiptSelectorSpec{requiredInputScalars: []string{"runId", "stepId"}}
}

func addMutationReceiptIdentityFields(spec mutationReceiptSelectorSpec) mutationReceiptSelectorSpec {
	// requestId/idempotencyKey are copied into the dedicated receipt field as
	// well, but retaining them in Identifiers keeps the existing compact receipt
	// shape compatible. The decoder validates either occurrence against input.
	return spec
}
