-- =============================================================
-- ARCHIVO: 12-webhooks.sql
-- DESCRIPCION: Sistema de webhooks, endpoints, entregas
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-10
-- EPIC: SAAS-INTEGRATIONS (EPIC-SAAS-005)
-- HISTORIAS: US-060, US-061
-- =============================================================

-- =====================
-- SCHEMA: webhooks
-- =====================
CREATE SCHEMA IF NOT EXISTS webhooks;

-- =====================
-- TABLA: webhooks.event_types
-- Tipos de eventos disponibles para webhooks
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.event_types (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Identificación
    code VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    category VARCHAR(50), -- sales, inventory, auth, billing, system

    -- Schema del payload
    payload_schema JSONB DEFAULT '{}',

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,
    is_internal BOOLEAN DEFAULT FALSE, -- Eventos internos no expuestos

    -- Metadata
    metadata JSONB DEFAULT '{}',

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- =====================
-- TABLA: webhooks.endpoints
-- Endpoints configurados por tenant
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.endpoints (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Identificación
    name VARCHAR(200) NOT NULL,
    description TEXT,

    -- URL destino
    url TEXT NOT NULL,
    http_method VARCHAR(10) DEFAULT 'POST',

    -- Autenticación
    auth_type VARCHAR(30) DEFAULT 'none', -- none, basic, bearer, hmac, oauth2
    auth_config JSONB DEFAULT '{}',
    -- basic: {username, password}
    -- bearer: {token}
    -- hmac: {secret, header_name, algorithm}
    -- oauth2: {client_id, client_secret, token_url}

    -- Headers personalizados
    custom_headers JSONB DEFAULT '{}',

    -- Eventos suscritos
    subscribed_events TEXT[] NOT NULL DEFAULT '{}',

    -- Filtros
    filters JSONB DEFAULT '{}',
    -- Ejemplo: {"branch_id": ["uuid1", "uuid2"], "amount_gte": 1000}

    -- Configuración de reintentos
    retry_enabled BOOLEAN DEFAULT TRUE,
    max_retries INTEGER DEFAULT 5,
    retry_delay_seconds INTEGER DEFAULT 60,
    retry_backoff_multiplier DECIMAL(3,1) DEFAULT 2.0,

    -- Timeouts
    timeout_seconds INTEGER DEFAULT 30,

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,
    is_verified BOOLEAN DEFAULT FALSE,
    verified_at TIMESTAMPTZ,

    -- Secreto para firma
    signing_secret VARCHAR(255),

    -- Estadísticas
    total_deliveries INTEGER DEFAULT 0,
    successful_deliveries INTEGER DEFAULT 0,
    failed_deliveries INTEGER DEFAULT 0,
    last_delivery_at TIMESTAMPTZ,
    last_success_at TIMESTAMPTZ,
    last_failure_at TIMESTAMPTZ,

    -- Rate limiting
    rate_limit_per_minute INTEGER DEFAULT 60,
    rate_limit_per_hour INTEGER DEFAULT 1000,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),

    UNIQUE(tenant_id, url)
);

-- =====================
-- TABLA: webhooks.deliveries
-- Log de entregas de webhooks
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.deliveries (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    endpoint_id UUID NOT NULL REFERENCES webhooks.endpoints(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Evento
    event_type VARCHAR(100) NOT NULL,
    event_id UUID NOT NULL,

    -- Payload enviado
    payload JSONB NOT NULL,
    payload_hash VARCHAR(64), -- SHA-256 para deduplicación

    -- Request
    request_url TEXT NOT NULL,
    request_method VARCHAR(10) NOT NULL,
    request_headers JSONB DEFAULT '{}',

    -- Response
    response_status INTEGER,
    response_headers JSONB DEFAULT '{}',
    response_body TEXT,
    response_time_ms INTEGER,

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'pending',
    -- pending, sending, delivered, failed, retrying, cancelled

    -- Reintentos
    attempt_number INTEGER DEFAULT 1,
    max_attempts INTEGER DEFAULT 5,
    next_retry_at TIMESTAMPTZ,

    -- Error info
    error_message TEXT,
    error_code VARCHAR(50),

    -- Timestamps
    scheduled_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    started_at TIMESTAMPTZ,
    completed_at TIMESTAMPTZ,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- =====================
-- TABLA: webhooks.events
-- Cola de eventos pendientes de envío
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Tipo de evento
    event_type VARCHAR(100) NOT NULL,

    -- Payload del evento
    payload JSONB NOT NULL,

    -- Contexto
    resource_type VARCHAR(100),
    resource_id UUID,
    triggered_by UUID REFERENCES auth.users(id),

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending, processing, dispatched, failed

    -- Procesamiento
    processed_at TIMESTAMPTZ,
    dispatched_endpoints INTEGER DEFAULT 0,
    failed_endpoints INTEGER DEFAULT 0,

    -- Deduplicación
    idempotency_key VARCHAR(255),

    -- Metadata
    metadata JSONB DEFAULT '{}',

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMPTZ
);

-- =====================
-- TABLA: webhooks.subscriptions
-- Suscripciones individuales evento-endpoint
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.subscriptions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    endpoint_id UUID NOT NULL REFERENCES webhooks.endpoints(id) ON DELETE CASCADE,
    event_type_id UUID NOT NULL REFERENCES webhooks.event_types(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Filtros específicos para esta suscripción
    filters JSONB DEFAULT '{}',

    -- Transformación del payload
    payload_template JSONB, -- Template para transformar el payload

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(endpoint_id, event_type_id)
);

-- =====================
-- TABLA: webhooks.endpoint_logs
-- Logs de actividad de endpoints
-- =====================
CREATE TABLE IF NOT EXISTS webhooks.endpoint_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    endpoint_id UUID NOT NULL REFERENCES webhooks.endpoints(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Tipo de log
    log_type VARCHAR(30) NOT NULL, -- config_changed, activated, deactivated, verified, error, rate_limited

    -- Detalles
    message TEXT,
    details JSONB DEFAULT '{}',

    -- Actor
    actor_id UUID REFERENCES auth.users(id),

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- =====================
-- INDICES
-- =====================

-- Indices para event_types
CREATE INDEX IF NOT EXISTS idx_event_types_code ON webhooks.event_types(code);
CREATE INDEX IF NOT EXISTS idx_event_types_category ON webhooks.event_types(category);
CREATE INDEX IF NOT EXISTS idx_event_types_active ON webhooks.event_types(is_active) WHERE is_active = TRUE;

-- Indices para endpoints
CREATE INDEX IF NOT EXISTS idx_endpoints_tenant ON webhooks.endpoints(tenant_id);
CREATE INDEX IF NOT EXISTS idx_endpoints_active ON webhooks.endpoints(is_active) WHERE is_active = TRUE;
CREATE INDEX IF NOT EXISTS idx_endpoints_events ON webhooks.endpoints USING GIN(subscribed_events);

-- Indices para deliveries
CREATE INDEX IF NOT EXISTS idx_deliveries_endpoint ON webhooks.deliveries(endpoint_id);
CREATE INDEX IF NOT EXISTS idx_deliveries_tenant ON webhooks.deliveries(tenant_id);
CREATE INDEX IF NOT EXISTS idx_deliveries_event ON webhooks.deliveries(event_type, event_id);
CREATE INDEX IF NOT EXISTS idx_deliveries_status ON webhooks.deliveries(status);
CREATE INDEX IF NOT EXISTS idx_deliveries_pending ON webhooks.deliveries(status, next_retry_at)
    WHERE status IN ('pending', 'retrying');
CREATE INDEX IF NOT EXISTS idx_deliveries_created ON webhooks.deliveries(created_at DESC);

-- Indices para events
CREATE INDEX IF NOT EXISTS idx_events_tenant ON webhooks.events(tenant_id);
CREATE INDEX IF NOT EXISTS idx_events_type ON webhooks.events(event_type);
CREATE INDEX IF NOT EXISTS idx_events_status ON webhooks.events(status);
CREATE INDEX IF NOT EXISTS idx_events_pending ON webhooks.events(status, created_at)
    WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS idx_events_idempotency ON webhooks.events(idempotency_key)
    WHERE idempotency_key IS NOT NULL;

-- Indices para subscriptions
CREATE INDEX IF NOT EXISTS idx_subs_endpoint ON webhooks.subscriptions(endpoint_id);
CREATE INDEX IF NOT EXISTS idx_subs_event_type ON webhooks.subscriptions(event_type_id);
CREATE INDEX IF NOT EXISTS idx_subs_tenant ON webhooks.subscriptions(tenant_id);

-- Indices para endpoint_logs
CREATE INDEX IF NOT EXISTS idx_endpoint_logs_endpoint ON webhooks.endpoint_logs(endpoint_id);
CREATE INDEX IF NOT EXISTS idx_endpoint_logs_created ON webhooks.endpoint_logs(created_at DESC);

-- =====================
-- RLS POLICIES
-- =====================

-- Event types son globales (lectura pública)
ALTER TABLE webhooks.event_types ENABLE ROW LEVEL SECURITY;
CREATE POLICY public_read_event_types ON webhooks.event_types
    FOR SELECT USING (is_active = TRUE AND is_internal = FALSE);

-- Endpoints por tenant
ALTER TABLE webhooks.endpoints ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_endpoints ON webhooks.endpoints
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Deliveries por tenant
ALTER TABLE webhooks.deliveries ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_deliveries ON webhooks.deliveries
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Events por tenant
ALTER TABLE webhooks.events ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_events ON webhooks.events
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Subscriptions por tenant
ALTER TABLE webhooks.subscriptions ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_subscriptions ON webhooks.subscriptions
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Endpoint logs por tenant
ALTER TABLE webhooks.endpoint_logs ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_endpoint_logs ON webhooks.endpoint_logs
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- =====================
-- FUNCIONES
-- =====================

-- Función para generar signing secret
CREATE OR REPLACE FUNCTION webhooks.generate_signing_secret()
RETURNS VARCHAR(255) AS $$
BEGIN
    RETURN 'whsec_' || encode(gen_random_bytes(32), 'hex');
END;
$$ LANGUAGE plpgsql;

-- Función para crear un endpoint con secreto
CREATE OR REPLACE FUNCTION webhooks.create_endpoint(
    p_tenant_id UUID,
    p_name VARCHAR(200),
    p_url TEXT,
    p_subscribed_events TEXT[],
    p_auth_type VARCHAR(30) DEFAULT 'none',
    p_auth_config JSONB DEFAULT '{}',
    p_created_by UUID DEFAULT NULL
)
RETURNS UUID AS $$
DECLARE
    v_endpoint_id UUID;
BEGIN
    INSERT INTO webhooks.endpoints (
        tenant_id, name, url, subscribed_events,
        auth_type, auth_config, signing_secret, created_by
    ) VALUES (
        p_tenant_id, p_name, p_url, p_subscribed_events,
        p_auth_type, p_auth_config, webhooks.generate_signing_secret(), p_created_by
    ) RETURNING id INTO v_endpoint_id;

    -- Log de creación
    INSERT INTO webhooks.endpoint_logs (endpoint_id, tenant_id, log_type, message, actor_id)
    VALUES (v_endpoint_id, p_tenant_id, 'created', 'Endpoint created', p_created_by);

    RETURN v_endpoint_id;
END;
$$ LANGUAGE plpgsql;

-- Función para emitir un evento
CREATE OR REPLACE FUNCTION webhooks.emit_event(
    p_tenant_id UUID,
    p_event_type VARCHAR(100),
    p_payload JSONB,
    p_resource_type VARCHAR(100) DEFAULT NULL,
    p_resource_id UUID DEFAULT NULL,
    p_triggered_by UUID DEFAULT NULL,
    p_idempotency_key VARCHAR(255) DEFAULT NULL
)
RETURNS UUID AS $$
DECLARE
    v_event_id UUID;
BEGIN
    -- Verificar deduplicación
    IF p_idempotency_key IS NOT NULL THEN
        SELECT id INTO v_event_id
        FROM webhooks.events
        WHERE tenant_id = p_tenant_id
        AND idempotency_key = p_idempotency_key
        AND created_at > CURRENT_TIMESTAMP - INTERVAL '24 hours';

        IF FOUND THEN
            RETURN v_event_id;
        END IF;
    END IF;

    -- Crear evento
    INSERT INTO webhooks.events (
        tenant_id, event_type, payload,
        resource_type, resource_id, triggered_by,
        idempotency_key, expires_at
    ) VALUES (
        p_tenant_id, p_event_type, p_payload,
        p_resource_type, p_resource_id, p_triggered_by,
        p_idempotency_key, CURRENT_TIMESTAMP + INTERVAL '7 days'
    ) RETURNING id INTO v_event_id;

    RETURN v_event_id;
END;
$$ LANGUAGE plpgsql;

-- Función para obtener endpoints suscritos a un evento
CREATE OR REPLACE FUNCTION webhooks.get_subscribed_endpoints(
    p_tenant_id UUID,
    p_event_type VARCHAR(100)
)
RETURNS TABLE (
    endpoint_id UUID,
    url TEXT,
    auth_type VARCHAR(30),
    auth_config JSONB,
    custom_headers JSONB,
    signing_secret VARCHAR(255),
    timeout_seconds INTEGER,
    filters JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        e.id as endpoint_id,
        e.url,
        e.auth_type,
        e.auth_config,
        e.custom_headers,
        e.signing_secret,
        e.timeout_seconds,
        e.filters
    FROM webhooks.endpoints e
    WHERE e.tenant_id = p_tenant_id
    AND e.is_active = TRUE
    AND p_event_type = ANY(e.subscribed_events);
END;
$$ LANGUAGE plpgsql STABLE;

-- Función para encolar entrega
CREATE OR REPLACE FUNCTION webhooks.queue_delivery(
    p_endpoint_id UUID,
    p_event_type VARCHAR(100),
    p_event_id UUID,
    p_payload JSONB
)
RETURNS UUID AS $$
DECLARE
    v_endpoint RECORD;
    v_delivery_id UUID;
BEGIN
    -- Obtener endpoint
    SELECT * INTO v_endpoint
    FROM webhooks.endpoints
    WHERE id = p_endpoint_id;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Endpoint not found: %', p_endpoint_id;
    END IF;

    -- Crear delivery
    INSERT INTO webhooks.deliveries (
        endpoint_id, tenant_id, event_type, event_id,
        payload, payload_hash,
        request_url, request_method, request_headers,
        max_attempts, status, scheduled_at
    ) VALUES (
        p_endpoint_id, v_endpoint.tenant_id, p_event_type, p_event_id,
        p_payload, encode(sha256(p_payload::text::bytea), 'hex'),
        v_endpoint.url, v_endpoint.http_method, v_endpoint.custom_headers,
        v_endpoint.max_retries + 1, 'pending', CURRENT_TIMESTAMP
    ) RETURNING id INTO v_delivery_id;

    RETURN v_delivery_id;
END;
$$ LANGUAGE plpgsql;

-- Función para marcar entrega como completada
CREATE OR REPLACE FUNCTION webhooks.mark_delivery_completed(
    p_delivery_id UUID,
    p_response_status INTEGER,
    p_response_headers JSONB,
    p_response_body TEXT,
    p_response_time_ms INTEGER
)
RETURNS BOOLEAN AS $$
DECLARE
    v_delivery RECORD;
    v_is_success BOOLEAN;
BEGIN
    SELECT * INTO v_delivery
    FROM webhooks.deliveries
    WHERE id = p_delivery_id;

    IF NOT FOUND THEN
        RETURN FALSE;
    END IF;

    v_is_success := p_response_status >= 200 AND p_response_status < 300;

    UPDATE webhooks.deliveries
    SET
        status = CASE WHEN v_is_success THEN 'delivered' ELSE 'failed' END,
        response_status = p_response_status,
        response_headers = p_response_headers,
        response_body = LEFT(p_response_body, 10000), -- Truncar respuesta larga
        response_time_ms = p_response_time_ms,
        completed_at = CURRENT_TIMESTAMP
    WHERE id = p_delivery_id;

    -- Actualizar estadísticas del endpoint
    UPDATE webhooks.endpoints
    SET
        total_deliveries = total_deliveries + 1,
        successful_deliveries = successful_deliveries + CASE WHEN v_is_success THEN 1 ELSE 0 END,
        failed_deliveries = failed_deliveries + CASE WHEN v_is_success THEN 0 ELSE 1 END,
        last_delivery_at = CURRENT_TIMESTAMP,
        last_success_at = CASE WHEN v_is_success THEN CURRENT_TIMESTAMP ELSE last_success_at END,
        last_failure_at = CASE WHEN v_is_success THEN last_failure_at ELSE CURRENT_TIMESTAMP END,
        updated_at = CURRENT_TIMESTAMP
    WHERE id = v_delivery.endpoint_id;

    RETURN v_is_success;
END;
$$ LANGUAGE plpgsql;

-- Función para programar reintento
CREATE OR REPLACE FUNCTION webhooks.schedule_retry(
    p_delivery_id UUID,
    p_error_message TEXT DEFAULT NULL
)
RETURNS BOOLEAN AS $$
DECLARE
    v_delivery RECORD;
    v_endpoint RECORD;
    v_delay_seconds INTEGER;
BEGIN
    SELECT d.*, e.retry_delay_seconds, e.retry_backoff_multiplier
    INTO v_delivery
    FROM webhooks.deliveries d
    JOIN webhooks.endpoints e ON e.id = d.endpoint_id
    WHERE d.id = p_delivery_id;

    IF NOT FOUND THEN
        RETURN FALSE;
    END IF;

    -- Verificar si quedan reintentos
    IF v_delivery.attempt_number >= v_delivery.max_attempts THEN
        UPDATE webhooks.deliveries
        SET status = 'failed', error_message = p_error_message, completed_at = CURRENT_TIMESTAMP
        WHERE id = p_delivery_id;
        RETURN FALSE;
    END IF;

    -- Calcular delay con backoff exponencial
    v_delay_seconds := v_delivery.retry_delay_seconds *
        POWER(v_delivery.retry_backoff_multiplier, v_delivery.attempt_number - 1);

    -- Programar reintento
    UPDATE webhooks.deliveries
    SET
        status = 'retrying',
        attempt_number = attempt_number + 1,
        next_retry_at = CURRENT_TIMESTAMP + (v_delay_seconds || ' seconds')::INTERVAL,
        error_message = p_error_message
    WHERE id = p_delivery_id;

    RETURN TRUE;
END;
$$ LANGUAGE plpgsql;

-- Función para obtener estadísticas de un endpoint
CREATE OR REPLACE FUNCTION webhooks.get_endpoint_stats(
    p_endpoint_id UUID,
    p_days INTEGER DEFAULT 7
)
RETURNS TABLE (
    total_deliveries BIGINT,
    successful BIGINT,
    failed BIGINT,
    success_rate DECIMAL,
    avg_response_time_ms DECIMAL,
    deliveries_by_day JSONB,
    errors_by_type JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        COUNT(*) as total_deliveries,
        COUNT(*) FILTER (WHERE d.status = 'delivered') as successful,
        COUNT(*) FILTER (WHERE d.status = 'failed') as failed,
        ROUND(
            COUNT(*) FILTER (WHERE d.status = 'delivered')::DECIMAL /
            NULLIF(COUNT(*), 0) * 100, 2
        ) as success_rate,
        ROUND(AVG(d.response_time_ms)::DECIMAL, 2) as avg_response_time_ms,
        jsonb_object_agg(
            COALESCE(DATE(d.created_at)::TEXT, 'unknown'),
            day_count
        ) as deliveries_by_day,
        jsonb_object_agg(
            COALESCE(d.error_code, 'unknown'),
            error_count
        ) FILTER (WHERE d.error_code IS NOT NULL) as errors_by_type
    FROM webhooks.deliveries d
    LEFT JOIN (
        SELECT DATE(created_at) as day, COUNT(*) as day_count
        FROM webhooks.deliveries
        WHERE endpoint_id = p_endpoint_id
        AND created_at > CURRENT_TIMESTAMP - (p_days || ' days')::INTERVAL
        GROUP BY DATE(created_at)
    ) days ON TRUE
    LEFT JOIN (
        SELECT error_code, COUNT(*) as error_count
        FROM webhooks.deliveries
        WHERE endpoint_id = p_endpoint_id
        AND error_code IS NOT NULL
        AND created_at > CURRENT_TIMESTAMP - (p_days || ' days')::INTERVAL
        GROUP BY error_code
    ) errors ON TRUE
    WHERE d.endpoint_id = p_endpoint_id
    AND d.created_at > CURRENT_TIMESTAMP - (p_days || ' days')::INTERVAL;
END;
$$ LANGUAGE plpgsql STABLE;

-- Función para limpiar entregas antiguas
CREATE OR REPLACE FUNCTION webhooks.cleanup_old_deliveries(p_days INTEGER DEFAULT 30)
RETURNS INTEGER AS $$
DECLARE
    deleted_count INTEGER;
BEGIN
    DELETE FROM webhooks.deliveries
    WHERE created_at < CURRENT_TIMESTAMP - (p_days || ' days')::INTERVAL
    AND status IN ('delivered', 'failed', 'cancelled');

    GET DIAGNOSTICS deleted_count = ROW_COUNT;

    -- También limpiar eventos procesados
    DELETE FROM webhooks.events
    WHERE created_at < CURRENT_TIMESTAMP - (p_days || ' days')::INTERVAL
    AND status = 'dispatched';

    RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;

-- =====================
-- TRIGGERS
-- =====================

CREATE OR REPLACE FUNCTION webhooks.update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_event_types_updated_at
    BEFORE UPDATE ON webhooks.event_types
    FOR EACH ROW EXECUTE FUNCTION webhooks.update_timestamp();

CREATE TRIGGER trg_endpoints_updated_at
    BEFORE UPDATE ON webhooks.endpoints
    FOR EACH ROW EXECUTE FUNCTION webhooks.update_timestamp();

CREATE TRIGGER trg_subscriptions_updated_at
    BEFORE UPDATE ON webhooks.subscriptions
    FOR EACH ROW EXECUTE FUNCTION webhooks.update_timestamp();

-- =====================
-- SEED DATA: Event Types
-- =====================
INSERT INTO webhooks.event_types (code, name, category, description, payload_schema) VALUES
-- Sales events
('sale.created', 'Venta Creada', 'sales', 'Se creó una nueva venta', '{"type": "object", "properties": {"sale_id": {"type": "string"}, "total": {"type": "number"}}}'),
('sale.completed', 'Venta Completada', 'sales', 'Una venta fue completada y pagada', '{}'),
('sale.cancelled', 'Venta Cancelada', 'sales', 'Una venta fue cancelada', '{}'),
('sale.refunded', 'Venta Reembolsada', 'sales', 'Se procesó un reembolso', '{}'),

-- Inventory events
('inventory.low_stock', 'Stock Bajo', 'inventory', 'Un producto alcanzó el nivel mínimo de stock', '{}'),
('inventory.out_of_stock', 'Sin Stock', 'inventory', 'Un producto se quedó sin stock', '{}'),
('inventory.adjusted', 'Inventario Ajustado', 'inventory', 'Se realizó un ajuste de inventario', '{}'),
('inventory.received', 'Mercancía Recibida', 'inventory', 'Se recibió mercancía en el almacén', '{}'),

-- Customer events
('customer.created', 'Cliente Creado', 'customers', 'Se registró un nuevo cliente', '{}'),
('customer.updated', 'Cliente Actualizado', 'customers', 'Se actualizó información del cliente', '{}'),

-- Auth events
('user.created', 'Usuario Creado', 'auth', 'Se creó un nuevo usuario', '{}'),
('user.login', 'Inicio de Sesión', 'auth', 'Un usuario inició sesión', '{}'),
('user.password_reset', 'Contraseña Restablecida', 'auth', 'Un usuario restableció su contraseña', '{}'),

-- Billing events
('subscription.created', 'Suscripción Creada', 'billing', 'Se creó una nueva suscripción', '{}'),
('subscription.renewed', 'Suscripción Renovada', 'billing', 'Se renovó una suscripción', '{}'),
('subscription.cancelled', 'Suscripción Cancelada', 'billing', 'Se canceló una suscripción', '{}'),
('invoice.created', 'Factura Creada', 'billing', 'Se generó una nueva factura', '{}'),
('invoice.paid', 'Factura Pagada', 'billing', 'Se pagó una factura', '{}'),
('payment.received', 'Pago Recibido', 'billing', 'Se recibió un pago', '{}'),
('payment.failed', 'Pago Fallido', 'billing', 'Un pago falló', '{}'),

-- System events
('system.maintenance', 'Mantenimiento Programado', 'system', 'Se programó mantenimiento del sistema', '{}'),
('system.alert', 'Alerta del Sistema', 'system', 'Se generó una alerta del sistema', '{}')

ON CONFLICT (code) DO NOTHING;

-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON TABLE webhooks.event_types IS 'Tipos de eventos disponibles para webhooks';
COMMENT ON TABLE webhooks.endpoints IS 'Endpoints configurados por tenant para recibir webhooks';
COMMENT ON TABLE webhooks.deliveries IS 'Log de entregas de webhooks con estado y reintentos';
COMMENT ON TABLE webhooks.events IS 'Cola de eventos pendientes de despacho';
COMMENT ON TABLE webhooks.subscriptions IS 'Suscripciones individuales evento-endpoint';
COMMENT ON TABLE webhooks.endpoint_logs IS 'Logs de actividad de endpoints';

COMMENT ON FUNCTION webhooks.emit_event IS 'Emite un evento a la cola de webhooks';
COMMENT ON FUNCTION webhooks.queue_delivery IS 'Encola una entrega de webhook';
COMMENT ON FUNCTION webhooks.mark_delivery_completed IS 'Marca una entrega como completada';
COMMENT ON FUNCTION webhooks.schedule_retry IS 'Programa un reintento de entrega';
COMMENT ON FUNCTION webhooks.get_endpoint_stats IS 'Obtiene estadísticas de un endpoint';
