package protosocket

import "strings"

type EventSubscriber interface {
	Subscribe(connectionID string, subscription EventSubscription) EventSubscription
}

type EventSubscription struct {
	Events []string
	RepoID string
	Branch string
}

func (s EventSubscription) Normalized() EventSubscription {
	events := make([]string, 0, len(s.Events))
	seen := make(map[string]struct{}, len(s.Events))
	for _, event := range s.Events {
		event = strings.TrimSpace(event)
		if event == "" {
			continue
		}
		if _, ok := seen[event]; ok {
			continue
		}
		seen[event] = struct{}{}
		events = append(events, event)
	}
	return EventSubscription{
		Events: events,
		RepoID: strings.TrimSpace(s.RepoID),
		Branch: strings.TrimSpace(s.Branch),
	}
}

func (s EventSubscription) Allows(env Envelope) bool {
	s = s.Normalized()
	if env.Type != "event" {
		return false
	}
	if !s.allowsEventName(env.Action, stringPayload(env.Payload, "type")) {
		return false
	}
	if s.RepoID != "" && s.RepoID != stringPayload(env.Payload, "repo_id") {
		return false
	}
	if s.Branch != "" && s.Branch != stringPayload(env.Payload, "branch") {
		return false
	}
	return true
}

func (s EventSubscription) Payload() map[string]any {
	s = s.Normalized()
	events := make([]any, 0, len(s.Events))
	for _, event := range s.Events {
		events = append(events, event)
	}
	return map[string]any{
		"events":  events,
		"repo_id": s.RepoID,
		"branch":  s.Branch,
	}
}

func (s EventSubscription) allowsEventName(action, payloadType string) bool {
	if len(s.Events) == 0 {
		return true
	}
	for _, event := range s.Events {
		if event == "*" || event == action || event == payloadType {
			return true
		}
	}
	return false
}

func stringPayload(payload map[string]any, key string) string {
	value, ok := payload[key]
	if !ok {
		return ""
	}
	text, ok := value.(string)
	if !ok {
		return ""
	}
	return strings.TrimSpace(text)
}
