package openwa

import "context"

// WebhooksService configures event delivery to external HTTP endpoints.
// Backed by src/modules/webhook/webhook.controller.ts.
type WebhooksService struct{ client *Client }

func (s *WebhooksService) base(sessionID string) string {
	return "/api/sessions/" + pathEscape(sessionID) + "/webhooks"
}

// ListAll returns webhooks across EVERY session the key can see, not one session's. Requires an
// OPERATOR-level key. The route pages with Limit and Offset only: query.SessionID is not sent, so use
// List for one session's webhooks.
func (s *WebhooksService) ListAll(ctx context.Context, query *DeliveryFailureQuery) ([]WebhookResponse, error) {
	var out []WebhookResponse
	values := query.values()
	values.Del("sessionId")
	err := s.client.do(ctx, "GET", "/api/webhooks", values, nil, &out)
	return out, err
}

// DeliveryFailures returns deliveries the gateway gave up on or could not dispatch: the diagnostic
// for a webhook that stopped arriving. Rows with Attempts > 0 exhausted their retries against the
// receiver. Rows with Attempts == 0 were not given up after retries: the payload was over the size
// cap or could not be serialized after the webhook:before hooks, dispatch capacity was shed, or
// shutdown interrupted the delivery (possibly between retries, after earlier attempts were sent). A
// row is removed once a later replay delivers the event. Requires an ADMIN-level key.
//
// A delivery a smart filter suppressed never reaches this log. Most recent first.
func (s *WebhooksService) DeliveryFailures(ctx context.Context, query *DeliveryFailureQuery) ([]WebhookDeliveryFailure, error) {
	var out []WebhookDeliveryFailure
	err := s.client.do(ctx, "GET", "/api/webhooks/delivery-failures", query.values(), nil, &out)
	return out, err
}

// RedriveDeliveryFailures replays recorded deliveries that still hold their event data
// (Replayable in DeliveryFailures), fewest attempts first, then oldest, one bounded batch per call.
// Each replay reuses the stored idempotency key, so a receiver that already handled the event can dedup it. Only rows
// recorded while the gateway's WEBHOOK_FAILURE_PAYLOAD_RETENTION_HOURS is above 0 are replayable.
// Requires an ADMIN-level key; rows outside the key's allowedSessions are never touched. A nil body
// uses the default batch filter.
func (s *WebhooksService) RedriveDeliveryFailures(ctx context.Context, body *RedriveWebhookDeliveriesRequest) (*WebhookRedriveResult, error) {
	if body == nil {
		body = &RedriveWebhookDeliveriesRequest{}
	}
	if body.IDs != nil && *body.IDs == nil {
		copy := *body
		empty := []string{}
		copy.IDs = &empty
		body = &copy
	}
	var out WebhookRedriveResult
	if err := s.client.do(ctx, "POST", "/api/webhooks/delivery-failures/redrive", nil, body, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

// List returns webhooks for a session.
func (s *WebhooksService) List(ctx context.Context, sessionID string) ([]WebhookResponse, error) {
	var out []WebhookResponse
	err := s.client.do(ctx, "GET", s.base(sessionID), nil, nil, &out)
	return out, err
}

// Get returns a single webhook.
func (s *WebhooksService) Get(ctx context.Context, sessionID, webhookID string) (*WebhookResponse, error) {
	var out WebhookResponse
	err := s.client.do(ctx, "GET", s.base(sessionID)+"/"+pathEscape(webhookID), nil, nil, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

// Create registers a webhook.
func (s *WebhooksService) Create(ctx context.Context, sessionID string, body CreateWebhookRequest) (*WebhookResponse, error) {
	var out WebhookResponse
	err := s.client.do(ctx, "POST", s.base(sessionID), nil, body, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

// Update modifies a webhook.
func (s *WebhooksService) Update(ctx context.Context, sessionID, webhookID string, body UpdateWebhookRequest) (*WebhookResponse, error) {
	var out WebhookResponse
	err := s.client.do(ctx, "PUT", s.base(sessionID)+"/"+pathEscape(webhookID), nil, body, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

// Delete removes a webhook.
func (s *WebhooksService) Delete(ctx context.Context, sessionID, webhookID string) error {
	return s.client.do(ctx, "DELETE", s.base(sessionID)+"/"+pathEscape(webhookID), nil, nil, nil)
}

// Test triggers a test delivery.
func (s *WebhooksService) Test(ctx context.Context, sessionID, webhookID string) (*WebhookTestResult, error) {
	var out WebhookTestResult
	err := s.client.do(ctx, "POST", s.base(sessionID)+"/"+pathEscape(webhookID)+"/test", nil, nil, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}
