package automation

import (
	"bytes"
	"encoding/json"
	"strings"
)

const automationRunMetadataTriggerContextKey = "trigger_context"

func automationRunMetadataJSON(existing string, triggerContextJSON string) string {
	raw := normalizedAutomationContractJSON(triggerContextJSON)
	if len(raw) == 0 {
		return strings.TrimSpace(existing)
	}
	envelope := map[string]json.RawMessage{}
	if trimmed := strings.TrimSpace(existing); trimmed != "" {
		var decoded map[string]json.RawMessage
		if err := json.Unmarshal([]byte(trimmed), &decoded); err == nil {
			envelope = decoded
		}
	}
	envelope[automationRunMetadataTriggerContextKey] = raw
	payload, _ := json.Marshal(envelope)
	return string(payload)
}

func automationRunTriggerContextJSON(metadata string) string {
	trimmed := strings.TrimSpace(metadata)
	if trimmed == "" {
		return ""
	}
	var envelope map[string]json.RawMessage
	if err := json.Unmarshal([]byte(trimmed), &envelope); err != nil {
		return ""
	}
	raw := bytes.TrimSpace(envelope[automationRunMetadataTriggerContextKey])
	if len(raw) == 0 || bytes.Equal(raw, []byte("null")) {
		return ""
	}
	return string(raw)
}

func normalizedAutomationContractJSON(value string) json.RawMessage {
	trimmed := strings.TrimSpace(value)
	if trimmed == "" {
		return nil
	}
	if json.Valid([]byte(trimmed)) {
		return json.RawMessage(trimmed)
	}
	encoded, _ := json.Marshal(trimmed)
	return encoded
}

func automationPushTriggerContextJSON(event AutomationRepositoryPushEventMutation) string {
	payload := map[string]any{
		"repository_full_name": strings.TrimSpace(event.RepositoryOwner) + "/" + strings.TrimSpace(event.RepositoryName),
		"ref":                  strings.TrimSpace(event.Ref),
		"branch":               automationBranchFromRef(event.Ref),
		"before_sha":           strings.TrimSpace(event.Before),
		"after_sha":            strings.TrimSpace(event.After),
		"trigger_kind":         "push",
	}
	if eventID := automationRepositoryPushEventIdentity(event); eventID != "" {
		payload["event_id"] = eventID
	}
	if actorRef := strings.TrimSpace(event.ActorRef); actorRef != "" {
		payload["actor_ref"] = actorRef
	}
	if actorDisplay := strings.TrimSpace(event.ActorDisplay); actorDisplay != "" {
		payload["actor_display"] = actorDisplay
	}
	return automationRunContractJSON(payload)
}

func automationBranchFromRef(ref string) string {
	trimmed := strings.TrimSpace(ref)
	const prefix = "refs/heads/"
	if strings.HasPrefix(trimmed, prefix) {
		return strings.TrimSpace(trimmed[len(prefix):])
	}
	return trimmed
}

func automationRunContractJSON(value any) string {
	payload, _ := json.Marshal(value)
	return string(payload)
}
