-- =============================================================================
-- ERP TRANSPORTISTAS - Schema Transport DDL
-- =============================================================================
-- Archivo: 01-transport-schema-ddl.sql
-- Version: 1.0.0
-- Fecha: 2026-01-25
-- Descripcion: Ordenes de transporte, embarques, viajes, paradas, POD
-- =============================================================================

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

CREATE TYPE transport.estado_orden AS ENUM (
  'BORRADOR',
  'CONFIRMADA',
  'ASIGNADA',
  'EN_PROCESO',
  'COMPLETADA',
  'FACTURADA',
  'CANCELADA'
);

CREATE TYPE transport.tipo_carga AS ENUM (
  'GENERAL',
  'PELIGROSA',
  'REFRIGERADA',
  'SOBREDIMENSIONADA',
  'GRANEL',
  'LIQUIDOS',
  'CONTENEDOR',
  'AUTOMOVILES'
);

CREATE TYPE transport.estado_pod AS ENUM (
  'PENDIENTE',
  'PARCIAL',
  'COMPLETO',
  'RECHAZADO'
);

-- =============================================================================
-- TABLA: ordenes_transporte (OT)
-- =============================================================================

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

  -- Identificación
  codigo VARCHAR(50) NOT NULL,
  referencia_cliente VARCHAR(100),

  -- Cliente (Shipper)
  shipper_id UUID NOT NULL,
  shipper_nombre VARCHAR(200) NOT NULL,

  -- Destinatario (Consignee)
  consignee_id UUID NOT NULL,
  consignee_nombre VARCHAR(200) NOT NULL,

  -- Origen
  origen_direccion TEXT NOT NULL,
  origen_codigo_postal VARCHAR(10),
  origen_ciudad VARCHAR(100),
  origen_estado VARCHAR(100),
  origen_pais VARCHAR(3) DEFAULT 'MEX',
  origen_latitud DECIMAL(10, 7),
  origen_longitud DECIMAL(10, 7),
  origen_contacto VARCHAR(200),
  origen_telefono VARCHAR(30),

  -- Destino
  destino_direccion TEXT NOT NULL,
  destino_codigo_postal VARCHAR(10),
  destino_ciudad VARCHAR(100),
  destino_estado VARCHAR(100),
  destino_pais VARCHAR(3) DEFAULT 'MEX',
  destino_latitud DECIMAL(10, 7),
  destino_longitud DECIMAL(10, 7),
  destino_contacto VARCHAR(200),
  destino_telefono VARCHAR(30),

  -- Fechas programadas
  fecha_recoleccion_programada TIMESTAMPTZ,
  fecha_entrega_programada TIMESTAMPTZ,
  ventana_recoleccion_inicio TIME,
  ventana_recoleccion_fin TIME,
  ventana_entrega_inicio TIME,
  ventana_entrega_fin TIME,

  -- Carga
  tipo_carga transport.tipo_carga DEFAULT 'GENERAL',
  descripcion_carga TEXT,
  peso_kg DECIMAL(12, 2),
  volumen_m3 DECIMAL(12, 4),
  piezas INT,
  pallets INT,
  valor_declarado DECIMAL(15, 2),
  moneda VARCHAR(3) DEFAULT 'MXN',

  -- Requisitos
  requiere_temperatura BOOLEAN DEFAULT FALSE,
  temperatura_min DECIMAL(5, 2),
  temperatura_max DECIMAL(5, 2),
  requiere_gps BOOLEAN DEFAULT FALSE,
  requiere_escolta BOOLEAN DEFAULT FALSE,
  requiere_cita BOOLEAN DEFAULT FALSE,
  instrucciones_especiales TEXT,

  -- Servicio y tarifa
  modalidad_servicio transport.modalidad_servicio DEFAULT 'FTL',
  tarifa_id UUID,
  tarifa_base DECIMAL(15, 2),
  recargos DECIMAL(15, 2) DEFAULT 0,
  descuentos DECIMAL(15, 2) DEFAULT 0,
  subtotal DECIMAL(15, 2),
  iva DECIMAL(15, 2),
  total DECIMAL(15, 2),

  -- Estado
  estado transport.estado_orden DEFAULT 'BORRADOR',

  -- Asignación
  viaje_id UUID,
  embarque_id UUID,

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

  CONSTRAINT uq_ot_tenant_codigo UNIQUE (tenant_id, codigo)
);

CREATE INDEX idx_ot_tenant ON transport.ordenes_transporte(tenant_id);
CREATE INDEX idx_ot_estado ON transport.ordenes_transporte(tenant_id, estado);
CREATE INDEX idx_ot_shipper ON transport.ordenes_transporte(tenant_id, shipper_id);
CREATE INDEX idx_ot_fechas ON transport.ordenes_transporte(tenant_id, fecha_recoleccion_programada);
CREATE INDEX idx_ot_viaje ON transport.ordenes_transporte(viaje_id) WHERE viaje_id IS NOT NULL;

-- =============================================================================
-- TABLA: embarques (Agrupación de OTs)
-- =============================================================================

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

  codigo VARCHAR(50) NOT NULL,
  descripcion VARCHAR(500),

  -- Cliente principal
  cliente_id UUID NOT NULL,

  -- Totales consolidados
  total_ots INT DEFAULT 0,
  peso_total_kg DECIMAL(12, 2),
  volumen_total_m3 DECIMAL(12, 4),

  -- Estado
  estado VARCHAR(20) DEFAULT 'ABIERTO',

  -- Viaje asignado
  viaje_id UUID,

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

  CONSTRAINT uq_embarque_tenant_codigo UNIQUE (tenant_id, codigo)
);

CREATE INDEX idx_embarque_tenant ON transport.embarques(tenant_id);
CREATE INDEX idx_embarque_cliente ON transport.embarques(tenant_id, cliente_id);

-- =============================================================================
-- TABLA: viajes
-- =============================================================================

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

  -- Identificación
  codigo VARCHAR(50) NOT NULL,

  -- Unidad y operador (referencias a fleet schema)
  unidad_id UUID NOT NULL,
  remolque_id UUID,
  operador_id UUID NOT NULL,

  -- Ruta
  origen_principal VARCHAR(200),
  destino_principal VARCHAR(200),
  distancia_estimada_km DECIMAL(10, 2),
  tiempo_estimado_horas DECIMAL(6, 2),

  -- Fechas programadas
  fecha_salida_programada TIMESTAMPTZ,
  fecha_llegada_programada TIMESTAMPTZ,

  -- Fechas reales
  fecha_salida_real TIMESTAMPTZ,
  fecha_llegada_real TIMESTAMPTZ,

  -- Kilometraje
  km_inicio INT,
  km_fin INT,
  km_recorridos INT GENERATED ALWAYS AS (km_fin - km_inicio) STORED,

  -- Estado
  estado transport.estado_viaje DEFAULT 'BORRADOR',

  -- Checklist pre-viaje
  checklist_completado BOOLEAN DEFAULT FALSE,
  checklist_fecha TIMESTAMPTZ,
  checklist_observaciones TEXT,

  -- Sellos
  sellos_salida JSONB,
  sellos_llegada JSONB,

  -- Costos
  costo_combustible DECIMAL(15, 2) DEFAULT 0,
  costo_peajes DECIMAL(15, 2) DEFAULT 0,
  costo_viaticos DECIMAL(15, 2) DEFAULT 0,
  costo_otros DECIMAL(15, 2) DEFAULT 0,
  costo_total DECIMAL(15, 2) DEFAULT 0,

  -- Ingresos
  ingreso_total DECIMAL(15, 2) DEFAULT 0,
  margen DECIMAL(15, 2) GENERATED ALWAYS AS (ingreso_total - costo_total) STORED,

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

  CONSTRAINT uq_viaje_tenant_codigo UNIQUE (tenant_id, codigo)
);

CREATE INDEX idx_viaje_tenant ON transport.viajes(tenant_id);
CREATE INDEX idx_viaje_estado ON transport.viajes(tenant_id, estado);
CREATE INDEX idx_viaje_unidad ON transport.viajes(tenant_id, unidad_id);
CREATE INDEX idx_viaje_operador ON transport.viajes(tenant_id, operador_id);
CREATE INDEX idx_viaje_fechas ON transport.viajes(tenant_id, fecha_salida_programada);

-- =============================================================================
-- TABLA: paradas_viaje (Multi-paradas)
-- =============================================================================

CREATE TABLE transport.paradas_viaje (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),
  viaje_id UUID NOT NULL REFERENCES transport.viajes(id),

  -- Secuencia
  secuencia INT NOT NULL,

  -- Tipo de parada
  tipo VARCHAR(20) NOT NULL, -- 'RECOLECCION', 'ENTREGA', 'ESCALA'

  -- Ubicación
  direccion TEXT NOT NULL,
  codigo_postal VARCHAR(10),
  ciudad VARCHAR(100),
  estado VARCHAR(100),
  latitud DECIMAL(10, 7),
  longitud DECIMAL(10, 7),

  -- Contacto
  contacto_nombre VARCHAR(200),
  contacto_telefono VARCHAR(30),

  -- Programación
  hora_programada_llegada TIMESTAMPTZ,
  hora_programada_salida TIMESTAMPTZ,

  -- Real
  hora_real_llegada TIMESTAMPTZ,
  hora_real_salida TIMESTAMPTZ,

  -- OTs asociadas
  ots_ids UUID[],

  -- Estado
  estado VARCHAR(20) DEFAULT 'PENDIENTE',

  -- Observaciones
  observaciones TEXT,

  CONSTRAINT uq_parada_viaje_secuencia UNIQUE (viaje_id, secuencia)
);

CREATE INDEX idx_parada_viaje ON transport.paradas_viaje(viaje_id);

-- =============================================================================
-- TABLA: pod (Proof of Delivery)
-- =============================================================================

CREATE TABLE transport.pod (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES public.tenants(id),
  viaje_id UUID NOT NULL REFERENCES transport.viajes(id),
  parada_id UUID REFERENCES transport.paradas_viaje(id),
  ot_id UUID REFERENCES transport.ordenes_transporte(id),

  -- Estado POD
  estado transport.estado_pod DEFAULT 'PENDIENTE',

  -- Recepción
  receptor_nombre VARCHAR(200),
  receptor_identificacion VARCHAR(50),
  fecha_recepcion TIMESTAMPTZ,

  -- Firma digital
  firma_digital TEXT, -- Base64 de la imagen de firma

  -- Evidencias (URLs o IDs de archivos)
  fotos_entrega JSONB,

  -- Cantidades
  piezas_entregadas INT,
  piezas_rechazadas INT,
  piezas_danadas INT,

  -- Observaciones
  observaciones TEXT,
  motivo_rechazo TEXT,

  -- Auditoría
  created_at TIMESTAMPTZ DEFAULT NOW(),
  created_by_id UUID,

  CONSTRAINT uq_pod_ot UNIQUE (ot_id)
);

CREATE INDEX idx_pod_viaje ON transport.pod(viaje_id);
CREATE INDEX idx_pod_estado ON transport.pod(tenant_id, estado);

-- =============================================================================
-- TABLA: incidencias
-- =============================================================================

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

  -- Referencias
  viaje_id UUID REFERENCES transport.viajes(id),
  ot_id UUID REFERENCES transport.ordenes_transporte(id),
  unidad_id UUID,
  operador_id UUID,

  -- Incidencia
  codigo VARCHAR(50) NOT NULL,
  tipo transport.tipo_incidencia NOT NULL,
  descripcion TEXT NOT NULL,

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

  -- Fecha/hora
  fecha_incidencia TIMESTAMPTZ NOT NULL,
  fecha_reporte TIMESTAMPTZ DEFAULT NOW(),

  -- Impacto
  tiempo_perdido_horas DECIMAL(6, 2),
  costo_estimado DECIMAL(15, 2),

  -- Resolución
  estado VARCHAR(20) DEFAULT 'ABIERTA',
  fecha_resolucion TIMESTAMPTZ,
  resolucion TEXT,
  responsable_id UUID,

  -- Evidencias
  evidencias JSONB,

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

  CONSTRAINT uq_incidencia_codigo UNIQUE (tenant_id, codigo)
);

CREATE INDEX idx_incidencia_tenant ON transport.incidencias(tenant_id);
CREATE INDEX idx_incidencia_viaje ON transport.incidencias(viaje_id) WHERE viaje_id IS NOT NULL;
CREATE INDEX idx_incidencia_estado ON transport.incidencias(tenant_id, estado);

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

ALTER TABLE transport.ordenes_transporte ENABLE ROW LEVEL SECURITY;
ALTER TABLE transport.embarques ENABLE ROW LEVEL SECURITY;
ALTER TABLE transport.viajes ENABLE ROW LEVEL SECURITY;
ALTER TABLE transport.paradas_viaje ENABLE ROW LEVEL SECURITY;
ALTER TABLE transport.pod ENABLE ROW LEVEL SECURITY;
ALTER TABLE transport.incidencias ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation_ot ON transport.ordenes_transporte
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_embarques ON transport.embarques
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_viajes ON transport.viajes
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_paradas ON transport.paradas_viaje
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_pod ON transport.pod
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation_incidencias ON transport.incidencias
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

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

COMMENT ON TABLE transport.ordenes_transporte IS 'Ordenes de transporte (OT) - solicitudes de servicio';
COMMENT ON TABLE transport.embarques IS 'Agrupación de OTs para consolidación';
COMMENT ON TABLE transport.viajes IS 'Ejecución operativa de transporte';
COMMENT ON TABLE transport.paradas_viaje IS 'Paradas programadas en un viaje (multi-drop)';
COMMENT ON TABLE transport.pod IS 'Proof of Delivery - evidencia de entrega';
COMMENT ON TABLE transport.incidencias IS 'Registro de incidencias durante el transporte';

-- =============================================================================
-- FIN DDL TRANSPORT
-- =============================================================================
