package cloud.nstart.terravault.ordinis.domain.webhook;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;

public interface WebhookDeliveryRepository extends JpaRepository<WebhookDelivery, Long> {

  /**
   * Due for retry: status IN (pending, retrying) AND next_attempt_at <= now().
   * Использует partial index {@code idx_webhook_deliveries_due}. Limit через
   * Pageable чтобы dispatcher не выгребал >1000 за тик.
   */
  @Query("""
      SELECT d FROM WebhookDelivery d
      WHERE d.status IN ('pending','retrying')
        AND d.nextAttemptAt <= :now
      ORDER BY d.nextAttemptAt ASC
      """)
  List<WebhookDelivery> findDue(@Param("now") OffsetDateTime now, Pageable pageable);

  /** DLQ листинг для admin UI. Partial index {@code idx_webhook_deliveries_dlq}. */
  Page<WebhookDelivery> findByStatus(WebhookDelivery.Status status, Pageable pageable);

  /** Метрика {@code nsi_webhook_dlq_count}. */
  long countByStatus(WebhookDelivery.Status status);

  /**
   * Idempotent insert (sub × event = uniq). На race между dispatcher tick'ами
   * вторая вставка попадёт в conflict, ON CONFLICT DO NOTHING. Native query
   * чтобы не тащить ON CONFLICT через JPA.
   */
  @Modifying
  @Query(value = """
      INSERT INTO webhook_deliveries (subscription_id, outbox_event_id, status,
                                      attempt_count, created_at, next_attempt_at)
      VALUES (:subscriptionId, :outboxEventId, 'pending', 0, now(), now())
      ON CONFLICT (subscription_id, outbox_event_id) DO NOTHING
      """, nativeQuery = true)
  int insertIfAbsent(
      @Param("subscriptionId") UUID subscriptionId,
      @Param("outboxEventId") Long outboxEventId);

  /** История доставок одного event'а — для drilldown в UI. */
  List<WebhookDelivery> findByOutboxEventIdOrderByCreatedAtDesc(Long outboxEventId);

  /** История доставок одной подписки. */
  Page<WebhookDelivery> findBySubscriptionIdOrderByCreatedAtDesc(
      UUID subscriptionId, Pageable pageable);

  /** История доставок одной подписки фильтрованная по status. */
  Page<WebhookDelivery> findBySubscriptionIdAndStatusOrderByCreatedAtDesc(
      UUID subscriptionId, WebhookDelivery.Status status, Pageable pageable);
}
