-- =====================================================
-- SISTEMA DE TRAZABILIDAD DE LOTES - ESQUEMA PRINCIPAL
-- =====================================================
-- Este esquema implementa un modelo de grafo para trazabilidad
-- de café desde ingreso de uva hasta secado final.
-- Permite rastrear divisiones, combinaciones y transformaciones.

-- Extensiones necesarias
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- =====================================================
-- TABLA: lotes
-- =====================================================
-- Representa cualquier estado físico del café en un momento dado.
-- Ejemplos: uva ingresada, café despulpado, café oreado, café secado, etc.

CREATE TABLE lotes (
  id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  codigo          TEXT UNIQUE,                    -- Código legible: UVA-001, SEC-042, etc.
  tipo            TEXT NOT NULL,                  -- uva, despulpado_primera, despulpado_segunda, despulpado_rechazos, oreado, presecado, reposo, secado
  fecha_creado    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  lugar_id        INTEGER,                        -- Referencia opcional a lugares (patio 1, pila 2, etc.)
  cantidad_kg     NUMERIC(10,2),                  -- Cantidad en kilogramos
  meta            JSONB,                          -- Información adicional (humedad, notas, etc.)

  CONSTRAINT lotes_cantidad_positiva CHECK (cantidad_kg IS NULL OR cantidad_kg >= 0),
  CONSTRAINT lotes_tipo_valido CHECK (tipo IN (
    'uva',
    'despulpado_primera',
    'despulpado_segunda',
    'despulpado_rechazos',
    'oreado',
    'presecado',
    'reposo',
    'secado'
  ))
);

-- Índices para búsquedas frecuentes
CREATE INDEX idx_lotes_tipo ON lotes(tipo);
CREATE INDEX idx_lotes_fecha_creado ON lotes(fecha_creado DESC);
CREATE INDEX idx_lotes_codigo ON lotes(codigo) WHERE codigo IS NOT NULL;

-- Comentarios
COMMENT ON TABLE lotes IS 'Representa cualquier estado físico del café en un momento dado';
COMMENT ON COLUMN lotes.codigo IS 'Código legible opcional para identificar el lote (ej: UVA-001, SEC-042)';
COMMENT ON COLUMN lotes.tipo IS 'Tipo de lote: uva, despulpado_*, oreado, presecado, reposo, secado';
COMMENT ON COLUMN lotes.meta IS 'Datos adicionales en formato JSON (ej: {humedad: 12.5, notas: "café especial"})';


-- =====================================================
-- TABLA: operaciones
-- =====================================================
-- Representa un evento donde lotes se transforman, combinan o dividen.
-- Ejemplos: ingreso de uva, despulpado, oreado, ajuste de merma, etc.

CREATE TABLE operaciones (
  id           UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tipo         TEXT NOT NULL,                      -- Tipo de operación
  fecha        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  lugar_id     INTEGER,                            -- Referencia opcional a lugares
  meta         JSONB,                              -- Información adicional específica del tipo

  CONSTRAINT operaciones_tipo_valido CHECK (tipo IN (
    -- Operaciones de proceso normal
    'ingreso',
    'despulpado',
    'oreado',
    'presecado',
    'reposo',
    'secado',
    'traslado',
    'mezcla',
    -- Operaciones de ajuste/corrección
    'ajuste_merma',
    'ajuste_cantidad',
    'ajuste_tipo',
    'correccion_asignacion',
    'fusion_manual',
    'division_manual'
  ))
);

-- Índices para búsquedas frecuentes
CREATE INDEX idx_operaciones_tipo ON operaciones(tipo);
CREATE INDEX idx_operaciones_fecha ON operaciones(fecha DESC);

-- Comentarios
COMMENT ON TABLE operaciones IS 'Eventos donde lotes se transforman, combinan o dividen';
COMMENT ON COLUMN operaciones.tipo IS 'Tipo de operación: ingreso, despulpado, oreado, ajuste_merma, etc.';
COMMENT ON COLUMN operaciones.meta IS 'Datos adicionales específicos del tipo de operación en formato JSON';


-- =====================================================
-- TABLA: operacion_lotes
-- =====================================================
-- Relación muchos a muchos entre operaciones y lotes.
-- Define qué lotes entran (input) y salen (output) de cada operación.

CREATE TABLE operacion_lotes (
  operacion_id  UUID NOT NULL REFERENCES operaciones(id) ON DELETE CASCADE,
  lote_id       UUID NOT NULL REFERENCES lotes(id) ON DELETE CASCADE,
  rol           TEXT NOT NULL,                      -- 'input' o 'output'
  cantidad_kg   NUMERIC(10,2),                      -- Cantidad específica usada/producida

  PRIMARY KEY (operacion_id, lote_id, rol),

  CONSTRAINT operacion_lotes_rol_valido CHECK (rol IN ('input', 'output')),
  CONSTRAINT operacion_lotes_cantidad_positiva CHECK (cantidad_kg IS NULL OR cantidad_kg > 0)
);

-- Índices para navegación del grafo
CREATE INDEX idx_operacion_lotes_operacion ON operacion_lotes(operacion_id);
CREATE INDEX idx_operacion_lotes_lote ON operacion_lotes(lote_id);
CREATE INDEX idx_operacion_lotes_rol ON operacion_lotes(rol);

-- Comentarios
COMMENT ON TABLE operacion_lotes IS 'Define qué lotes entran y salen de cada operación (grafo de trazabilidad)';
COMMENT ON COLUMN operacion_lotes.rol IS 'input: lote usado en la operación | output: lote producido por la operación';
COMMENT ON COLUMN operacion_lotes.cantidad_kg IS 'Cantidad en kg que participó en esta relación específica';


-- =====================================================
-- FUNCIÓN: get_trazabilidad
-- =====================================================
-- Obtiene el historial completo de un lote caminando el grafo hacia atrás.
-- Retorna todos los lotes ancestros hasta llegar a los ingresos iniciales.

CREATE OR REPLACE FUNCTION get_trazabilidad(lote_id_inicial UUID)
RETURNS TABLE (
  lote_id       UUID,
  codigo        TEXT,
  tipo          TEXT,
  cantidad_kg   NUMERIC,
  operacion_id  UUID,
  operacion_tipo TEXT,
  profundidad   INTEGER
) AS $$
BEGIN
  RETURN QUERY
  WITH RECURSIVE trazabilidad AS (
    -- Punto de partida: el lote final
    SELECT
      l.id AS lote_id,
      l.codigo,
      l.tipo,
      l.cantidad_kg,
      ol.operacion_id,
      o.tipo AS operacion_tipo,
      0 AS profundidad
    FROM lotes l
    LEFT JOIN operacion_lotes ol ON ol.lote_id = l.id AND ol.rol = 'output'
    LEFT JOIN operaciones o ON o.id = ol.operacion_id
    WHERE l.id = lote_id_inicial

    UNION ALL

    -- Caminar hacia atrás: buscar lotes que fueron inputs
    SELECT
      l2.id AS lote_id,
      l2.codigo,
      l2.tipo,
      l2.cantidad_kg,
      ol2.operacion_id,
      o2.tipo AS operacion_tipo,
      t.profundidad + 1
    FROM trazabilidad t
    JOIN operacion_lotes ol_in
      ON ol_in.operacion_id = t.operacion_id
     AND ol_in.rol = 'input'
    JOIN lotes l2
      ON l2.id = ol_in.lote_id
    LEFT JOIN operacion_lotes ol2
      ON ol2.lote_id = l2.id
     AND ol2.rol = 'output'
    LEFT JOIN operaciones o2
      ON o2.id = ol2.operacion_id
    WHERE t.operacion_id IS NOT NULL  -- Solo continuar si hay operación
  )
  SELECT * FROM trazabilidad
  ORDER BY profundidad, tipo, codigo;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_trazabilidad IS 'Obtiene el historial completo de un lote caminando el grafo hacia atrás';


-- =====================================================
-- VISTA: vista_lotes_con_origen
-- =====================================================
-- Vista útil que muestra cada lote con información de la operación que lo creó.

CREATE OR REPLACE VIEW vista_lotes_con_origen AS
SELECT
  l.id,
  l.codigo,
  l.tipo,
  l.fecha_creado,
  l.cantidad_kg,
  l.meta,
  o.id AS operacion_id,
  o.tipo AS operacion_tipo,
  o.fecha AS operacion_fecha
FROM lotes l
LEFT JOIN operacion_lotes ol
  ON ol.lote_id = l.id
 AND ol.rol = 'output'
LEFT JOIN operaciones o
  ON o.id = ol.operacion_id;

COMMENT ON VIEW vista_lotes_con_origen IS 'Muestra lotes con información de la operación que los creó';


-- =====================================================
-- MENSAJES DE ÉXITO
-- =====================================================
DO $$
BEGIN
  RAISE NOTICE '✓ Esquema de trazabilidad creado exitosamente';
  RAISE NOTICE '  - Tabla lotes creada';
  RAISE NOTICE '  - Tabla operaciones creada';
  RAISE NOTICE '  - Tabla operacion_lotes creada';
  RAISE NOTICE '  - Función get_trazabilidad() creada';
  RAISE NOTICE '  - Vista vista_lotes_con_origen creada';
END $$;
