package com.cameleer.server.core.alerting;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

public interface AlertInstanceRepository {
    AlertInstance save(AlertInstance instance);
    Optional<AlertInstance> findById(UUID id);

    /** Open instance for a rule: state IN ('PENDING','FIRING') AND deleted_at IS NULL. */
    Optional<AlertInstance> findOpenForRule(UUID ruleId);

    /** Unfiltered inbox listing — convenience overload. */
    default List<AlertInstance> listForInbox(UUID environmentId,
                                             List<String> userGroupIdFilter,
                                             String userId,
                                             List<String> userRoleNames,
                                             int limit) {
        return listForInbox(environmentId, userGroupIdFilter, userId, userRoleNames,
                null, null, null, null, limit);
    }

    /**
     * Inbox listing with optional filters. {@code null} or empty lists mean no filter.
     * {@code acked} and {@code read} are tri-state: {@code null} = no filter,
     * {@code TRUE} = only acked/read, {@code FALSE} = only unacked/unread.
     * Always excludes soft-deleted rows ({@code deleted_at IS NOT NULL}).
     */
    List<AlertInstance> listForInbox(UUID environmentId,
                                     List<String> userGroupIdFilter,
                                     String userId,
                                     List<String> userRoleNames,
                                     List<AlertState> states,
                                     List<AlertSeverity> severities,
                                     Boolean acked,
                                     Boolean read,
                                     int limit);

    /**
     * Count unread alert instances visible to the user, grouped by severity.
     * Visibility: targets user directly, or via one of the given groups/roles.
     * "Unread" = {@code read_at IS NULL AND deleted_at IS NULL}.
     * Always returns a map with an entry for every {@link AlertSeverity} (value 0 if no rows),
     * so callers never need null-checks.
     */
    Map<AlertSeverity, Long> countUnreadBySeverity(UUID environmentId,
                                                    String userId,
                                                    List<String> groupIds,
                                                    List<String> roleNames);

    void ack(UUID id, String userId, Instant when);
    void resolve(UUID id, Instant when);
    void markSilenced(UUID id, boolean silenced);
    void deleteResolvedBefore(Instant cutoff);

    /** Set {@code read_at = when} if currently null. Idempotent. */
    void markRead(UUID id, Instant when);
    /** Bulk variant — single UPDATE. */
    void bulkMarkRead(List<UUID> ids, Instant when);

    /** Set {@code deleted_at = when} if currently null. Idempotent. */
    void softDelete(UUID id, Instant when);
    /** Bulk variant — single UPDATE. */
    void bulkSoftDelete(List<UUID> ids, Instant when);

    /** Clear {@code deleted_at}. Undo for soft-delete. Idempotent. */
    void restore(UUID id);

    /** Bulk ack — single UPDATE. Each row gets {@code acked_at=when, acked_by=userId} if unacked. */
    void bulkAck(List<UUID> ids, String userId, Instant when);

    List<AlertInstance> listFiringDueForReNotify(Instant now);

    /**
     * Filter the given IDs to those that exist in the given environment and are not
     * soft-deleted. Single SQL round-trip — avoids N+1 in bulk operations.
     */
    List<UUID> filterInEnvLive(List<UUID> ids, UUID environmentId);
}
