package manage

import (
	"context"
	"strings"
)

type ListFilter struct {
	SourceKind          SourceKind
	EventKind           string
	TargetKind          TargetKind
	TargetRef           string
	Status              string
	IncludeChildThreads bool
	Limit               int
	Offset              int
	Page                bool
}

const (
	DefaultListLimit = 20
	MaxListLimit     = 100
)

func (service *Service) ListForOwner(ctx context.Context, ownerUserID string, workspaceID string) ([]TriggerView, error) {
	return service.ListForOwnerWithFilter(ctx, ownerUserID, workspaceID, ListFilter{})
}

func (service *Service) ListForOwnerWithFilter(ctx context.Context, ownerUserID string, workspaceID string, filter ListFilter) ([]TriggerView, error) {
	normalized, err := normalizeTriggerListFilter(filter)
	if err != nil {
		return nil, err
	}
	fetchLimit := normalized.Limit + normalized.Offset
	if fetchLimit < normalized.Limit {
		fetchLimit = normalized.Limit
	}
	if fetchLimit > MaxListLimit+1 {
		fetchLimit = MaxListLimit + 1
	}
	views, err := service.listScheduleDefinitionsForOwner(ctx, ownerUserID, workspaceID, fetchLimit)
	if err != nil {
		return nil, err
	}
	views = filterTriggerViews(views, normalized)
	if normalized.Offset >= len(views) {
		return []TriggerView{}, nil
	}
	views = views[normalized.Offset:]
	if len(views) > normalized.Limit {
		views = views[:normalized.Limit]
	}
	return views, nil
}

func filterTriggerViews(views []TriggerView, filter ListFilter) []TriggerView {
	filtered := make([]TriggerView, 0, len(views))
	for _, view := range views {
		if filter.Status != "" && !strings.EqualFold(string(view.Status), filter.Status) {
			continue
		}
		if filter.TargetKind != "" && (view.Target.Kind != filter.TargetKind || strings.TrimSpace(view.Target.Ref) != filter.TargetRef) {
			continue
		}
		filtered = append(filtered, view)
	}
	return filtered
}

func (service *Service) ListSummariesForOwnerWithFilter(ctx context.Context, ownerUserID string, workspaceID string, filter ListFilter) ([]TriggerSummaryView, error) {
	views, err := service.ListForOwnerWithFilter(ctx, ownerUserID, workspaceID, filter)
	if err != nil {
		return nil, err
	}
	summaries := make([]TriggerSummaryView, 0, len(views))
	for _, view := range views {
		summaries = append(summaries, summaryFromTriggerView(view))
	}
	return summaries, nil
}

func summaryFromTriggerView(view TriggerView) TriggerSummaryView {
	return TriggerSummaryView{
		ID:               view.ID,
		Name:             view.Name,
		Status:           view.Status,
		SourceKind:       view.SourceKind,
		TimeMode:         view.TimeMode,
		Target:           view.Target,
		NextOccurrenceAt: view.NextOccurrenceAt,
		LastFailureCode:  view.LastFailureCode,
	}
}

func normalizeTriggerListFilter(filter ListFilter) (ListFilter, error) {
	normalized := ListFilter{
		SourceKind:          SourceKind(strings.TrimSpace(strings.ToLower(string(filter.SourceKind)))),
		EventKind:           strings.TrimSpace(strings.ToLower(filter.EventKind)),
		TargetKind:          TargetKind(strings.TrimSpace(strings.ToLower(string(filter.TargetKind)))),
		TargetRef:           strings.TrimSpace(filter.TargetRef),
		Status:              strings.TrimSpace(strings.ToLower(filter.Status)),
		IncludeChildThreads: filter.IncludeChildThreads,
		Limit:               filter.Limit,
		Offset:              filter.Offset,
		Page:                filter.Page,
	}
	if (normalized.TargetKind == "") != (normalized.TargetRef == "") {
		return ListFilter{}, badRequest("target_kind and target_ref must be provided together")
	}
	switch normalized.TargetKind {
	case "", TargetKindChannel, TargetKindReplyThread, TargetKindDM, TargetKindTask:
	default:
		return ListFilter{}, badRequest("target_kind must be `channel`, `reply_thread`, `dm`, or `task`")
	}
	if normalized.IncludeChildThreads && normalized.TargetKind != TargetKindChannel && normalized.TargetKind != TargetKindDM {
		return ListFilter{}, badRequest("include_child_threads requires a channel or DM target")
	}
	switch normalized.SourceKind {
	case "":
		normalized.SourceKind = SourceKindTime
	case SourceKindTime:
	case SourceKindEvent:
		return ListFilter{}, badRequest("source_kind_not_enabled")
	default:
		return ListFilter{}, badRequest("source_kind must be `time`")
	}
	if normalized.EventKind != "" {
		return ListFilter{}, badRequest("event_kind is not enabled for generic Trigger management")
	}
	maxLimit := MaxListLimit
	if normalized.Page {
		maxLimit++
	}
	if normalized.Limit <= 0 {
		normalized.Limit = DefaultListLimit
	} else if normalized.Limit > maxLimit {
		normalized.Limit = maxLimit
	}
	if normalized.Offset < 0 {
		normalized.Offset = 0
	}
	return normalized, nil
}

func (service *Service) GetForOwner(ctx context.Context, ownerUserID string, workspaceID string, triggerID string) (TriggerView, error) {
	route, err := service.resolveScheduleRoute(ctx, ownerUserID, workspaceID, triggerID)
	if err != nil {
		return TriggerView{}, err
	}
	owner, err := service.loadManageOwner(ctx, workspaceID, ownerUserID)
	if err != nil {
		return TriggerView{}, err
	}
	definition, err := service.loadScheduleDefinitionForOwner(ctx, workspaceID, owner.MemberID, route.TargetID)
	if err != nil {
		return TriggerView{}, err
	}
	return service.viewFromScheduleRoute(ctx, ownerUserID, route, definition, true)
}

func (service *Service) ListRunsForOwner(ctx context.Context, ownerUserID string, workspaceID string, triggerID string, limit int) ([]RunView, error) {
	route, err := service.resolveScheduleRoute(ctx, ownerUserID, workspaceID, triggerID)
	if err != nil {
		return nil, err
	}
	return service.listAutomationRunsForSchedule(ctx, ownerUserID, workspaceID, route, normalizeTriggerRunListLimit(limit))
}

func normalizeTriggerRunListLimit(limit int) int {
	switch {
	case limit <= 0:
		return DefaultListLimit
	case limit > MaxListLimit:
		return MaxListLimit
	default:
		return limit
	}
}

// Keep the authoritative schedule source in one place for the compatibility-named
// trigger list facade. No trigger projection or alias rows participate.
