-- =============================================================================
-- ERP TRANSPORTISTAS - Schema Tracking DDL
-- =============================================================================
-- Archivo: 03-tracking-schema-ddl.sql
-- Version: 1.0.0
-- Fecha: 2026-01-25
-- Descripcion: Eventos GPS, geocercas, alertas, posiciones
-- =============================================================================

-- =============================================================================
-- TIPOS ENUMERADOS ADICIONALES
-- =============================================================================

CREATE TYPE tracking.tipo_geocerca AS ENUM (
  'CLIENTE',
  'PROVEEDOR',
  'PATIO',
  'ZONA_RIESGO',
  'CASETA',
  'GASOLINERA',
  'PUNTO_CONTROL',
  'OTRO'
);

CREATE TYPE tracking.severidad_alerta AS ENUM (
  'INFO',
  'WARNING',
  'CRITICAL'
);

CREATE TYPE tracking.tipo_alerta AS ENUM (
  'ENTRADA_GEOCERCA',
  'SALIDA_GEOCERCA',
  'EXCESO_VELOCIDAD',
  'PARADA_PROLONGADA',
  'DESVIO_RUTA',
  'TEMPERATURA_FUERA_RANGO',
  'BATERIA_BAJA',
  'SIN_SENAL',
  'BOTON_PANICO',
  'APERTURA_PUERTA',
  'CONSUMO_ANOMALO'
);

-- =============================================================================
-- TABLA: posiciones_gps
-- =============================================================================

CREATE TABLE tracking.posiciones_gps (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  -- Unidad
  unidad_id UUID NOT NULL,

  -- Posición
  latitud DECIMAL(10, 7) NOT NULL,
  longitud DECIMAL(10, 7) NOT NULL,
  altitud DECIMAL(8, 2),

  -- Velocidad y dirección
  velocidad_kmh DECIMAL(6, 2),
  rumbo INT, -- 0-360 grados

  -- Timestamp
  timestamp_gps TIMESTAMPTZ NOT NULL,
  timestamp_servidor TIMESTAMPTZ DEFAULT NOW(),

  -- Datos adicionales GPS
  hdop DECIMAL(4, 2), -- Dilución de precisión horizontal
  satelites INT,

  -- Estado del vehículo
  motor_encendido BOOLEAN,
  odometro INT,

  -- Proveedor
  proveedor_gps VARCHAR(50),
  imei VARCHAR(50),

  -- Viaje asociado (si está en viaje)
  viaje_id UUID,

  -- Partición por fecha
  fecha_particion DATE NOT NULL DEFAULT CURRENT_DATE
) PARTITION BY RANGE (fecha_particion);

-- Crear particiones mensuales (ejemplo para 2026)
CREATE TABLE tracking.posiciones_gps_2026_01 PARTITION OF tracking.posiciones_gps
  FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

CREATE TABLE tracking.posiciones_gps_2026_02 PARTITION OF tracking.posiciones_gps
  FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');

CREATE TABLE tracking.posiciones_gps_2026_03 PARTITION OF tracking.posiciones_gps
  FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');

CREATE INDEX idx_posicion_unidad_fecha ON tracking.posiciones_gps(unidad_id, timestamp_gps);
CREATE INDEX idx_posicion_viaje ON tracking.posiciones_gps(viaje_id) WHERE viaje_id IS NOT NULL;
CREATE INDEX idx_posicion_geo ON tracking.posiciones_gps USING GIST (
  ST_SetSRID(ST_MakePoint(longitud, latitud), 4326)
);

-- =============================================================================
-- TABLA: eventos_tracking
-- =============================================================================

CREATE TABLE tracking.eventos (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  -- Viaje
  viaje_id UUID NOT NULL,

  -- Tipo y fuente
  tipo_evento tracking.tipo_evento NOT NULL,
  fuente tracking.fuente_evento NOT NULL,

  -- Ubicación
  latitud DECIMAL(10, 7),
  longitud DECIMAL(10, 7),
  direccion TEXT,

  -- Timestamp
  timestamp_evento TIMESTAMPTZ NOT NULL,
  timestamp_registro TIMESTAMPTZ DEFAULT NOW(),

  -- Datos específicos del evento
  datos JSONB,

  -- Parada asociada (si aplica)
  parada_id UUID,

  -- Usuario/Operador que generó
  generado_por_id UUID,
  generado_por_tipo VARCHAR(20), -- 'OPERADOR', 'SISTEMA', 'USUARIO'

  -- Evidencias
  evidencias JSONB,

  -- Observaciones
  observaciones TEXT
);

CREATE INDEX idx_evento_viaje ON tracking.eventos(viaje_id);
CREATE INDEX idx_evento_tipo ON tracking.eventos(tenant_id, tipo_evento);
CREATE INDEX idx_evento_fecha ON tracking.eventos(timestamp_evento);

-- =============================================================================
-- TABLA: geocercas
-- =============================================================================

CREATE TABLE tracking.geocercas (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  -- Identificación
  codigo VARCHAR(50) NOT NULL,
  nombre VARCHAR(200) NOT NULL,
  tipo tracking.tipo_geocerca NOT NULL,

  -- Geometría (polígono o círculo)
  es_circular BOOLEAN DEFAULT FALSE,

  -- Para geocerca circular
  centro_latitud DECIMAL(10, 7),
  centro_longitud DECIMAL(10, 7),
  radio_metros DECIMAL(10, 2),

  -- Para geocerca poligonal (GeoJSON)
  poligono GEOMETRY(POLYGON, 4326),

  -- Asociación
  cliente_id UUID, -- Si tipo = CLIENTE
  direccion TEXT,

  -- Alertas
  alerta_entrada BOOLEAN DEFAULT TRUE,
  alerta_salida BOOLEAN DEFAULT TRUE,
  tiempo_permanencia_minutos INT, -- Alerta si permanece más de X minutos

  -- Configuración
  color VARCHAR(7) DEFAULT '#FF0000',
  activa BOOLEAN DEFAULT TRUE,

  -- Auditoría
  created_at TIMESTAMPTZ DEFAULT NOW(),
  created_by_id UUID NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_geocerca_tenant ON tracking.geocercas(tenant_id);
CREATE INDEX idx_geocerca_tipo ON tracking.geocercas(tenant_id, tipo);
CREATE INDEX idx_geocerca_geo ON tracking.geocercas USING GIST (poligono);
CREATE UNIQUE INDEX idx_geocerca_codigo ON tracking.geocercas(tenant_id, codigo);

-- =============================================================================
-- TABLA: alertas
-- =============================================================================

CREATE TABLE tracking.alertas (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  -- Tipo y severidad
  tipo tracking.tipo_alerta NOT NULL,
  severidad tracking.severidad_alerta NOT NULL,

  -- Referencias
  unidad_id UUID,
  viaje_id UUID,
  geocerca_id UUID REFERENCES tracking.geocercas(id),
  operador_id UUID,

  -- Ubicación
  latitud DECIMAL(10, 7),
  longitud DECIMAL(10, 7),

  -- Descripción
  titulo VARCHAR(200) NOT NULL,
  mensaje TEXT NOT NULL,

  -- Datos específicos
  datos JSONB,

  -- Timestamp
  timestamp_alerta TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  -- Estado
  leida BOOLEAN DEFAULT FALSE,
  leida_por UUID,
  leida_fecha TIMESTAMPTZ,

  atendida BOOLEAN DEFAULT FALSE,
  atendida_por UUID,
  atendida_fecha TIMESTAMPTZ,
  resolucion TEXT,

  -- Notificaciones enviadas
  notificaciones_enviadas JSONB
);

CREATE INDEX idx_alerta_tenant ON tracking.alertas(tenant_id);
CREATE INDEX idx_alerta_unidad ON tracking.alertas(unidad_id);
CREATE INDEX idx_alerta_viaje ON tracking.alertas(viaje_id);
CREATE INDEX idx_alerta_no_atendida ON tracking.alertas(tenant_id, atendida) WHERE atendida = FALSE;
CREATE INDEX idx_alerta_fecha ON tracking.alertas(timestamp_alerta);

-- =============================================================================
-- TABLA: reglas_alerta
-- =============================================================================

CREATE TABLE tracking.reglas_alerta (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  -- Identificación
  nombre VARCHAR(200) NOT NULL,
  descripcion TEXT,

  -- Tipo de alerta que genera
  tipo_alerta tracking.tipo_alerta NOT NULL,
  severidad tracking.severidad_alerta DEFAULT 'WARNING',

  -- Condiciones (JSON con configuración)
  condiciones JSONB NOT NULL,
  -- Ejemplo: { "velocidad_max": 100, "tiempo_parada_max_min": 30, "temp_min": -18, "temp_max": -15 }

  -- Aplicabilidad
  aplica_todas_unidades BOOLEAN DEFAULT TRUE,
  unidades_ids UUID[],
  aplica_todos_viajes BOOLEAN DEFAULT TRUE,

  -- Notificaciones
  notificar_email BOOLEAN DEFAULT TRUE,
  notificar_sms BOOLEAN DEFAULT FALSE,
  notificar_push BOOLEAN DEFAULT TRUE,
  destinatarios JSONB, -- Array de {tipo, id, email, telefono}

  -- Estado
  activa BOOLEAN DEFAULT TRUE,

  -- Auditoría
  created_at TIMESTAMPTZ DEFAULT NOW(),
  created_by_id UUID NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_regla_tenant ON tracking.reglas_alerta(tenant_id);
CREATE INDEX idx_regla_tipo ON tracking.reglas_alerta(tipo_alerta) WHERE activa = TRUE;

-- =============================================================================
-- TABLA: eta_calculado
-- =============================================================================

CREATE TABLE tracking.eta_calculado (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),

  viaje_id UUID NOT NULL,
  parada_id UUID,

  -- ETA
  eta_original TIMESTAMPTZ,
  eta_actual TIMESTAMPTZ NOT NULL,
  eta_anterior TIMESTAMPTZ,

  -- Cálculo
  distancia_restante_km DECIMAL(10, 2),
  tiempo_restante_minutos INT,

  -- Factores
  factor_trafico DECIMAL(3, 2) DEFAULT 1.00,
  factor_clima DECIMAL(3, 2) DEFAULT 1.00,

  -- Estado
  estado VARCHAR(20), -- 'EN_TIEMPO', 'ADELANTADO', 'RETRASADO'
  minutos_diferencia INT,

  -- Timestamp
  calculado_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_eta_viaje ON tracking.eta_calculado(viaje_id);
CREATE INDEX idx_eta_fecha ON tracking.eta_calculado(calculado_at);

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

ALTER TABLE tracking.posiciones_gps ENABLE ROW LEVEL SECURITY;
ALTER TABLE tracking.eventos ENABLE ROW LEVEL SECURITY;
ALTER TABLE tracking.geocercas ENABLE ROW LEVEL SECURITY;
ALTER TABLE tracking.alertas ENABLE ROW LEVEL SECURITY;
ALTER TABLE tracking.reglas_alerta ENABLE ROW LEVEL SECURITY;
ALTER TABLE tracking.eta_calculado ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation_posiciones ON tracking.posiciones_gps
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_eventos ON tracking.eventos
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_geocercas ON tracking.geocercas
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_alertas ON tracking.alertas
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_reglas ON tracking.reglas_alerta
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_eta ON tracking.eta_calculado
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

-- =============================================================================
-- COMENTARIOS
-- =============================================================================

COMMENT ON TABLE tracking.posiciones_gps IS 'Posiciones GPS de unidades (particionada por fecha)';
COMMENT ON TABLE tracking.eventos IS 'Eventos de tracking durante viajes';
COMMENT ON TABLE tracking.geocercas IS 'Geocercas/zonas de interés';
COMMENT ON TABLE tracking.alertas IS 'Alertas generadas por el sistema de tracking';
COMMENT ON TABLE tracking.reglas_alerta IS 'Reglas de configuración para generar alertas';
COMMENT ON TABLE tracking.eta_calculado IS 'Historial de cálculos de ETA';

-- =============================================================================
-- FIN DDL TRACKING
-- =============================================================================
