-- ============================================
-- WEBHOOKS: Delivery Log Table
-- ============================================

-- Delivery attempts table
CREATE TABLE webhooks.deliveries (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  webhook_id UUID NOT NULL REFERENCES webhooks.webhooks(id) ON DELETE CASCADE,
  tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,

  -- Event info
  event_type TEXT NOT NULL,
  payload JSONB NOT NULL,

  -- Delivery status
  status webhooks.delivery_status NOT NULL DEFAULT 'pending',

  -- Response info
  response_status INTEGER,
  response_body TEXT,
  response_headers JSONB,

  -- Retry tracking
  attempt INTEGER NOT NULL DEFAULT 1,
  max_attempts INTEGER NOT NULL DEFAULT 5,
  next_retry_at TIMESTAMPTZ,
  last_error TEXT,

  -- Timestamps
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  delivered_at TIMESTAMPTZ,
  completed_at TIMESTAMPTZ
);

-- Indexes
CREATE INDEX idx_deliveries_webhook ON webhooks.deliveries(webhook_id);
CREATE INDEX idx_deliveries_tenant ON webhooks.deliveries(tenant_id);
CREATE INDEX idx_deliveries_status ON webhooks.deliveries(status) WHERE status IN ('pending', 'retrying');
CREATE INDEX idx_deliveries_retry ON webhooks.deliveries(next_retry_at) WHERE status = 'retrying' AND next_retry_at IS NOT NULL;
CREATE INDEX idx_deliveries_created ON webhooks.deliveries(created_at DESC);

-- RLS
ALTER TABLE webhooks.deliveries ENABLE ROW LEVEL SECURITY;

CREATE POLICY deliveries_tenant_isolation ON webhooks.deliveries
  FOR ALL
  USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Function to calculate next retry time with exponential backoff
CREATE OR REPLACE FUNCTION webhooks.calculate_next_retry(attempt INTEGER)
RETURNS TIMESTAMPTZ AS $$
BEGIN
  -- Retry schedule: 1min, 5min, 30min, 2hours, 6hours
  RETURN CASE attempt
    WHEN 1 THEN NOW() + INTERVAL '1 minute'
    WHEN 2 THEN NOW() + INTERVAL '5 minutes'
    WHEN 3 THEN NOW() + INTERVAL '30 minutes'
    WHEN 4 THEN NOW() + INTERVAL '2 hours'
    WHEN 5 THEN NOW() + INTERVAL '6 hours'
    ELSE NULL -- No more retries
  END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- Function to get pending deliveries for retry
CREATE OR REPLACE FUNCTION webhooks.get_pending_retries(batch_size INTEGER DEFAULT 100)
RETURNS SETOF webhooks.deliveries AS $$
BEGIN
  RETURN QUERY
  SELECT *
  FROM webhooks.deliveries
  WHERE status = 'retrying'
    AND next_retry_at <= NOW()
  ORDER BY next_retry_at ASC
  LIMIT batch_size
  FOR UPDATE SKIP LOCKED;
END;
$$ LANGUAGE plpgsql;

-- Function to get delivery stats for a webhook
CREATE OR REPLACE FUNCTION webhooks.get_webhook_stats(p_webhook_id UUID)
RETURNS TABLE (
  total_deliveries BIGINT,
  successful_deliveries BIGINT,
  failed_deliveries BIGINT,
  pending_deliveries BIGINT,
  success_rate NUMERIC,
  last_delivery_at TIMESTAMPTZ
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    COUNT(*)::BIGINT as total_deliveries,
    COUNT(*) FILTER (WHERE status = 'delivered')::BIGINT as successful_deliveries,
    COUNT(*) FILTER (WHERE status = 'failed')::BIGINT as failed_deliveries,
    COUNT(*) FILTER (WHERE status IN ('pending', 'retrying'))::BIGINT as pending_deliveries,
    CASE
      WHEN COUNT(*) FILTER (WHERE status IN ('delivered', 'failed')) > 0
      THEN ROUND(
        COUNT(*) FILTER (WHERE status = 'delivered')::NUMERIC /
        COUNT(*) FILTER (WHERE status IN ('delivered', 'failed'))::NUMERIC * 100, 2
      )
      ELSE 0
    END as success_rate,
    MAX(delivered_at) as last_delivery_at
  FROM webhooks.deliveries
  WHERE webhook_id = p_webhook_id;
END;
$$ LANGUAGE plpgsql STABLE;

-- Comments
COMMENT ON TABLE webhooks.deliveries IS 'Webhook delivery attempts and status tracking';
COMMENT ON COLUMN webhooks.deliveries.attempt IS 'Current attempt number (1-based)';
COMMENT ON COLUMN webhooks.deliveries.next_retry_at IS 'When to retry if status is retrying';
COMMENT ON FUNCTION webhooks.calculate_next_retry IS 'Calculate next retry time with exponential backoff';
COMMENT ON FUNCTION webhooks.get_pending_retries IS 'Get deliveries ready for retry processing';
COMMENT ON FUNCTION webhooks.get_webhook_stats IS 'Get delivery statistics for a webhook';
