-- Prueba de extremo a extremo con un índice vectorial real. REQUIERE pgvector,
-- por eso no corre en `make installcheck` sino en `make installcheck-vector`.
--
-- Las aserciones son de RANGO y no de valor exacto: measure() muestrea consultas
-- al azar, así que un test que exigiera "0.9000" fallaría cada tantas corridas.
-- Un test que falla a veces se termina ignorando, y un test ignorado no protege
-- nada.

CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_recall_guard CASCADE;

-- Corpus chico pero suficiente para que HNSW tenga que elegir: 2.000 vectores
-- de 32 dimensiones, deterministas (setseed) para que el índice sea el mismo en
-- cada corrida.
SELECT setseed(0.42);
CREATE TABLE rg_items (id serial PRIMARY KEY, embedding vector(32));
INSERT INTO rg_items (embedding)
SELECT array_agg(random())::vector(32)
  FROM generate_series(1, 2000) g, generate_series(1, 32) d
 GROUP BY g;

CREATE INDEX rg_items_hnsw ON rg_items USING hnsw (embedding vector_cosine_ops);
ANALYZE rg_items;

-- 1. El descubrimiento lo encuentra, con su access method y su operador.
SELECT table_name, access_method, operator, column_name
  FROM recall_guard.vector_indexes WHERE index_name = 'rg_items_hnsw';

-- 2. Con el índice sano el recall es alto.
SET hnsw.ef_search = 100;
SELECT recall_guard.measure('rg_items_hnsw'::regclass, 10, 10) >= 0.90 AS sano_es_alto;

-- 3. Y con el índice estrangulado se DERRUMBA. Esta es la aserción que de verdad
--    importa: si el recall no bajara, la herramienta no estaría midiendo nada y
--    todos los demás números serían decorativos.
SET hnsw.ef_search = 1;
SELECT recall_guard.measure('rg_items_hnsw'::regclass, 10, 10) < 0.50 AS roto_se_derrumba;

-- 4. El self-match no puede sostener el piso: con ef_search=1 el recall tiene que
--    poder llegar a cero. Antes de descartar el ctid de origen daba exactamente
--    0.1000 (=1/10), el vector encontrándose a sí mismo.
SELECT recall_guard.measure('rg_items_hnsw'::regclass, 10, 10) < 0.10 AS sin_piso_artificial;

-- 5. Cada medición queda registrada.
SELECT count(*) >= 3 AS mediciones_guardadas
  FROM recall_guard.measurements WHERE index_name = 'rg_items_hnsw';

-- 6. El ciclo completo: aprobar sano, degradar, y que check() lo llame crítico.
SET hnsw.ef_search = 100;
SELECT recall_guard.approve('rg_items_hnsw'::regclass, 10, 10, 'test') >= 0.90 AS baseline_alto;

SET hnsw.ef_search = 1;
SELECT index_name, baseline >= 0.90 AS baseline_alto, current < 0.50 AS bajo, verdict
  FROM recall_guard.check();

RESET hnsw.ef_search;
DROP TABLE rg_items CASCADE;
