-- =====================================================
-- SCHEMA: system
-- PROPÓSITO: Mensajería, notificaciones, logs, reportes
-- MÓDULOS: MGN-012 (Reportes), MGN-014 (Mensajería)
-- FECHA: 2025-11-24
-- =====================================================

-- Crear schema
CREATE SCHEMA IF NOT EXISTS system;

-- =====================================================
-- TYPES (ENUMs)
-- =====================================================

CREATE TYPE system.message_type AS ENUM (
  'comment',
  'note',
  'email',
  'notification',
  'system'
);

CREATE TYPE system.notification_status AS ENUM (
  'pending',
  'sent',
  'read',
  'failed'
);

CREATE TYPE system.activity_type AS ENUM (
  'call',
  'meeting',
  'email',
  'todo',
  'follow_up',
  'custom'
);

CREATE TYPE system.activity_status AS ENUM (
  'planned',
  'done',
  'cancelled',
  'overdue'
);

CREATE TYPE system.email_status AS ENUM (
  'draft',
  'queued',
  'sending',
  'sent',
  'failed',
  'bounced'
);

CREATE TYPE system.log_level AS ENUM (
  'debug',
  'info',
  'warning',
  'error',
  'critical'
);

CREATE TYPE system.report_format AS ENUM (
  'pdf',
  'excel',
  'csv',
  'html'
);

-- =====================================================
-- TABLES
-- =====================================================

-- Tabla: messages (Chatter - mensajes en registros)
CREATE TABLE system.messages (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  -- Referencia polimórfica (a qué registro pertenece)
  model VARCHAR(100) NOT NULL, -- 'SaleOrder', 'Task', 'Invoice', etc.
  record_id UUID NOT NULL,

  -- Tipo y contenido
  message_type system.message_type NOT NULL DEFAULT 'comment',
  subject VARCHAR(255),
  body TEXT NOT NULL,

  -- Autor
  author_id UUID REFERENCES auth.users(id),
  author_name VARCHAR(255),
  author_email VARCHAR(255),

  -- Email tracking
  email_from VARCHAR(255),
  reply_to VARCHAR(255),
  message_id VARCHAR(500), -- Message-ID para threading

  -- Relación (respuesta a mensaje)
  parent_id UUID REFERENCES system.messages(id),

  -- Attachments
  attachment_ids UUID[] DEFAULT '{}',

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP
);

-- Tabla: message_followers (Seguidores de registros)
CREATE TABLE system.message_followers (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  -- Referencia polimórfica
  model VARCHAR(100) NOT NULL,
  record_id UUID NOT NULL,

  -- Seguidor
  partner_id UUID REFERENCES core.partners(id),
  user_id UUID REFERENCES auth.users(id),

  -- Configuración
  email_notifications BOOLEAN DEFAULT TRUE,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT uq_message_followers UNIQUE (model, record_id, COALESCE(user_id, partner_id)),
  CONSTRAINT chk_message_followers_user_or_partner CHECK (
    (user_id IS NOT NULL AND partner_id IS NULL) OR
    (partner_id IS NOT NULL AND user_id IS NULL)
  )
);

-- Tabla: notifications (Notificaciones a usuarios)
CREATE TABLE system.notifications (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

  -- Contenido
  title VARCHAR(255) NOT NULL,
  message TEXT NOT NULL,
  url VARCHAR(500), -- URL para acción (ej: /sales/orders/123)

  -- Referencia (opcional)
  model VARCHAR(100),
  record_id UUID,

  -- Estado
  status system.notification_status NOT NULL DEFAULT 'pending',
  read_at TIMESTAMP,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  sent_at TIMESTAMP
);

-- Tabla: activities (Actividades programadas)
CREATE TABLE system.activities (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  -- Referencia polimórfica
  model VARCHAR(100) NOT NULL,
  record_id UUID NOT NULL,

  -- Actividad
  activity_type system.activity_type NOT NULL,
  summary VARCHAR(255) NOT NULL,
  description TEXT,

  -- Asignación
  assigned_to UUID REFERENCES auth.users(id),
  assigned_by UUID REFERENCES auth.users(id),

  -- Fechas
  due_date DATE NOT NULL,
  due_time TIME,

  -- Estado
  status system.activity_status NOT NULL DEFAULT 'planned',

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  completed_at TIMESTAMP,
  completed_by UUID REFERENCES auth.users(id)
);

-- Tabla: message_templates (Plantillas de mensajes/emails)
CREATE TABLE system.message_templates (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  name VARCHAR(255) NOT NULL,
  model VARCHAR(100), -- Para qué modelo se usa

  -- Contenido
  subject VARCHAR(255),
  body_html TEXT,
  body_text TEXT,

  -- Configuración email
  email_from VARCHAR(255),
  reply_to VARCHAR(255),
  cc VARCHAR(255),
  bcc VARCHAR(255),

  -- Control
  active BOOLEAN DEFAULT TRUE,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES auth.users(id),

  CONSTRAINT uq_message_templates_name_tenant UNIQUE (tenant_id, name)
);

-- Tabla: email_queue (Cola de envío de emails)
CREATE TABLE system.email_queue (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID REFERENCES auth.tenants(id),

  -- Destinatarios
  email_to VARCHAR(255) NOT NULL,
  email_cc VARCHAR(500),
  email_bcc VARCHAR(500),

  -- Contenido
  subject VARCHAR(255) NOT NULL,
  body_html TEXT,
  body_text TEXT,

  -- Remitente
  email_from VARCHAR(255) NOT NULL,
  reply_to VARCHAR(255),

  -- Attachments
  attachment_ids UUID[] DEFAULT '{}',

  -- Estado
  status system.email_status NOT NULL DEFAULT 'queued',
  attempts INTEGER DEFAULT 0,
  max_attempts INTEGER DEFAULT 3,
  error_message TEXT,

  -- Tracking
  message_id VARCHAR(500),
  opened_at TIMESTAMP,
  clicked_at TIMESTAMP,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  scheduled_at TIMESTAMP,
  sent_at TIMESTAMP,
  failed_at TIMESTAMP
);

-- Tabla: logs (Logs del sistema)
CREATE TABLE system.logs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID REFERENCES auth.tenants(id),

  -- Nivel y fuente
  level system.log_level NOT NULL,
  logger VARCHAR(100), -- Módulo que genera el log

  -- Mensaje
  message TEXT NOT NULL,
  stack_trace TEXT,

  -- Contexto
  user_id UUID REFERENCES auth.users(id),
  ip_address INET,
  user_agent TEXT,
  request_id UUID,

  -- Referencia (opcional)
  model VARCHAR(100),
  record_id UUID,

  -- Metadata adicional
  metadata JSONB DEFAULT '{}',

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- Tabla: reports (Definiciones de reportes)
CREATE TABLE system.reports (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  name VARCHAR(255) NOT NULL,
  code VARCHAR(50) NOT NULL,
  description TEXT,

  -- Tipo
  model VARCHAR(100), -- Para qué modelo es el reporte
  report_type VARCHAR(50), -- 'standard', 'custom', 'dashboard'

  -- Query/Template
  query_template TEXT, -- SQL template o JSON query
  template_file VARCHAR(255), -- Path al archivo de plantilla

  -- Configuración
  default_format system.report_format DEFAULT 'pdf',
  is_public BOOLEAN DEFAULT FALSE,

  -- Control
  active BOOLEAN DEFAULT TRUE,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES auth.users(id),

  CONSTRAINT uq_reports_code_tenant UNIQUE (tenant_id, code)
);

-- Tabla: report_executions (Ejecuciones de reportes)
CREATE TABLE system.report_executions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  report_id UUID NOT NULL REFERENCES system.reports(id) ON DELETE CASCADE,

  -- Parámetros de ejecución
  parameters JSONB DEFAULT '{}',
  format system.report_format NOT NULL,

  -- Resultado
  file_url VARCHAR(500),
  file_size BIGINT,
  error_message TEXT,

  -- Estado
  status VARCHAR(20) DEFAULT 'pending', -- pending, running, completed, failed

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  started_at TIMESTAMP,
  completed_at TIMESTAMP
);

-- Tabla: dashboards (Dashboards configurables)
CREATE TABLE system.dashboards (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

  name VARCHAR(255) NOT NULL,
  description TEXT,

  -- Configuración
  layout JSONB DEFAULT '{}', -- Grid layout configuration
  is_default BOOLEAN DEFAULT FALSE,

  -- Visibilidad
  user_id UUID REFERENCES auth.users(id), -- NULL = compartido
  is_public BOOLEAN DEFAULT FALSE,

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES auth.users(id),

  CONSTRAINT uq_dashboards_name_user UNIQUE (tenant_id, name, COALESCE(user_id, '00000000-0000-0000-0000-000000000000'::UUID))
);

-- Tabla: dashboard_widgets (Widgets en dashboards)
CREATE TABLE system.dashboard_widgets (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  dashboard_id UUID NOT NULL REFERENCES system.dashboards(id) ON DELETE CASCADE,

  -- Tipo de widget
  widget_type VARCHAR(50) NOT NULL, -- 'chart', 'kpi', 'table', 'calendar', etc.
  title VARCHAR(255),

  -- Configuración
  config JSONB NOT NULL DEFAULT '{}', -- Widget-specific configuration
  position JSONB DEFAULT '{}', -- {x, y, w, h} para grid

  -- Data source
  data_source VARCHAR(100), -- Model o query
  query_params JSONB DEFAULT '{}',

  -- Refresh
  refresh_interval INTEGER, -- Segundos

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP
);

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

-- Messages
CREATE INDEX idx_messages_tenant_id ON system.messages(tenant_id);
CREATE INDEX idx_messages_model_record ON system.messages(model, record_id);
CREATE INDEX idx_messages_author_id ON system.messages(author_id);
CREATE INDEX idx_messages_parent_id ON system.messages(parent_id);
CREATE INDEX idx_messages_created_at ON system.messages(created_at DESC);

-- Message Followers
CREATE INDEX idx_message_followers_model_record ON system.message_followers(model, record_id);
CREATE INDEX idx_message_followers_user_id ON system.message_followers(user_id);
CREATE INDEX idx_message_followers_partner_id ON system.message_followers(partner_id);

-- Notifications
CREATE INDEX idx_notifications_tenant_id ON system.notifications(tenant_id);
CREATE INDEX idx_notifications_user_id ON system.notifications(user_id);
CREATE INDEX idx_notifications_status ON system.notifications(status);
CREATE INDEX idx_notifications_model_record ON system.notifications(model, record_id);
CREATE INDEX idx_notifications_created_at ON system.notifications(created_at DESC);

-- Activities
CREATE INDEX idx_activities_tenant_id ON system.activities(tenant_id);
CREATE INDEX idx_activities_model_record ON system.activities(model, record_id);
CREATE INDEX idx_activities_assigned_to ON system.activities(assigned_to);
CREATE INDEX idx_activities_due_date ON system.activities(due_date);
CREATE INDEX idx_activities_status ON system.activities(status);

-- Message Templates
CREATE INDEX idx_message_templates_tenant_id ON system.message_templates(tenant_id);
CREATE INDEX idx_message_templates_model ON system.message_templates(model);
CREATE INDEX idx_message_templates_active ON system.message_templates(active) WHERE active = TRUE;

-- Email Queue
CREATE INDEX idx_email_queue_status ON system.email_queue(status);
CREATE INDEX idx_email_queue_scheduled_at ON system.email_queue(scheduled_at);
CREATE INDEX idx_email_queue_created_at ON system.email_queue(created_at);

-- Logs
CREATE INDEX idx_logs_tenant_id ON system.logs(tenant_id);
CREATE INDEX idx_logs_level ON system.logs(level);
CREATE INDEX idx_logs_logger ON system.logs(logger);
CREATE INDEX idx_logs_user_id ON system.logs(user_id);
CREATE INDEX idx_logs_created_at ON system.logs(created_at DESC);
CREATE INDEX idx_logs_model_record ON system.logs(model, record_id);

-- Reports
CREATE INDEX idx_reports_tenant_id ON system.reports(tenant_id);
CREATE INDEX idx_reports_code ON system.reports(code);
CREATE INDEX idx_reports_active ON system.reports(active) WHERE active = TRUE;

-- Report Executions
CREATE INDEX idx_report_executions_tenant_id ON system.report_executions(tenant_id);
CREATE INDEX idx_report_executions_report_id ON system.report_executions(report_id);
CREATE INDEX idx_report_executions_created_by ON system.report_executions(created_by);
CREATE INDEX idx_report_executions_created_at ON system.report_executions(created_at DESC);

-- Dashboards
CREATE INDEX idx_dashboards_tenant_id ON system.dashboards(tenant_id);
CREATE INDEX idx_dashboards_user_id ON system.dashboards(user_id);
CREATE INDEX idx_dashboards_is_public ON system.dashboards(is_public) WHERE is_public = TRUE;

-- Dashboard Widgets
CREATE INDEX idx_dashboard_widgets_dashboard_id ON system.dashboard_widgets(dashboard_id);
CREATE INDEX idx_dashboard_widgets_type ON system.dashboard_widgets(widget_type);

-- =====================================================
-- FUNCTIONS
-- =====================================================

-- Función: notify_followers
CREATE OR REPLACE FUNCTION system.notify_followers(
  p_model VARCHAR,
  p_record_id UUID,
  p_message_id UUID
)
RETURNS VOID AS $$
BEGIN
  INSERT INTO system.notifications (tenant_id, user_id, title, message, model, record_id)
  SELECT
    get_current_tenant_id(),
    mf.user_id,
    'New message in ' || p_model,
    m.body,
    p_model,
    p_record_id
  FROM system.message_followers mf
  JOIN system.messages m ON m.id = p_message_id
  WHERE mf.model = p_model
    AND mf.record_id = p_record_id
    AND mf.user_id IS NOT NULL
    AND mf.email_notifications = TRUE;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION system.notify_followers IS 'Notifica a los seguidores de un registro cuando hay un nuevo mensaje';

-- Función: mark_activity_as_overdue
CREATE OR REPLACE FUNCTION system.mark_activities_as_overdue()
RETURNS INTEGER AS $$
DECLARE
  v_updated_count INTEGER;
BEGIN
  WITH updated AS (
    UPDATE system.activities
    SET status = 'overdue'
    WHERE status = 'planned'
      AND due_date < CURRENT_DATE
    RETURNING id
  )
  SELECT COUNT(*) INTO v_updated_count FROM updated;

  RETURN v_updated_count;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION system.mark_activities_as_overdue IS 'Marca actividades vencidas como overdue (ejecutar diariamente)';

-- Función: clean_old_logs
CREATE OR REPLACE FUNCTION system.clean_old_logs(p_days_to_keep INTEGER DEFAULT 90)
RETURNS INTEGER AS $$
DECLARE
  v_deleted_count INTEGER;
BEGIN
  WITH deleted AS (
    DELETE FROM system.logs
    WHERE created_at < CURRENT_TIMESTAMP - (p_days_to_keep || ' days')::INTERVAL
      AND level != 'critical'
    RETURNING id
  )
  SELECT COUNT(*) INTO v_deleted_count FROM deleted;

  RETURN v_deleted_count;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION system.clean_old_logs IS 'Limpia logs antiguos (mantener solo críticos)';

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

CREATE TRIGGER trg_messages_updated_at
  BEFORE UPDATE ON system.messages
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_message_templates_updated_at
  BEFORE UPDATE ON system.message_templates
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_reports_updated_at
  BEFORE UPDATE ON system.reports
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_dashboards_updated_at
  BEFORE UPDATE ON system.dashboards
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_dashboard_widgets_updated_at
  BEFORE UPDATE ON system.dashboard_widgets
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

-- =====================================================
-- ROW LEVEL SECURITY (RLS)
-- =====================================================

ALTER TABLE system.messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.notifications ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.activities ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.message_templates ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.reports ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.report_executions ENABLE ROW LEVEL SECURITY;
ALTER TABLE system.dashboards ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation_messages ON system.messages
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_notifications ON system.notifications
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_activities ON system.activities
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_message_templates ON system.message_templates
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_logs ON system.logs
  USING (tenant_id = get_current_tenant_id() OR tenant_id IS NULL);

CREATE POLICY tenant_isolation_reports ON system.reports
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_report_executions ON system.report_executions
  USING (tenant_id = get_current_tenant_id());

CREATE POLICY tenant_isolation_dashboards ON system.dashboards
  USING (tenant_id = get_current_tenant_id());

-- =====================================================
-- TRACKING AUTOMÁTICO (mail.thread pattern de Odoo)
-- =====================================================

-- Tabla: field_tracking_config (Configuración de campos a trackear)
CREATE TABLE system.field_tracking_config (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  table_schema VARCHAR(50) NOT NULL,
  table_name VARCHAR(100) NOT NULL,
  field_name VARCHAR(100) NOT NULL,
  track_changes BOOLEAN NOT NULL DEFAULT true,
  field_type VARCHAR(50) NOT NULL, -- 'text', 'integer', 'numeric', 'boolean', 'uuid', 'timestamp', 'json'
  display_label VARCHAR(255) NOT NULL, -- Para mostrar en UI: "Estado", "Monto", "Cliente", etc.
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT uq_field_tracking UNIQUE (table_schema, table_name, field_name)
);

-- Índice para búsqueda rápida
CREATE INDEX idx_field_tracking_config_table
ON system.field_tracking_config(table_schema, table_name);

-- Tabla: change_log (Historial de cambios en registros)
CREATE TABLE system.change_log (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id),

  -- Referencia al registro modificado
  table_schema VARCHAR(50) NOT NULL,
  table_name VARCHAR(100) NOT NULL,
  record_id UUID NOT NULL,

  -- Usuario que hizo el cambio
  changed_by UUID NOT NULL REFERENCES auth.users(id),
  changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  -- Tipo de cambio
  change_type VARCHAR(20) NOT NULL CHECK (change_type IN ('create', 'update', 'delete', 'state_change')),

  -- Campo modificado (NULL para create/delete)
  field_name VARCHAR(100),
  field_label VARCHAR(255), -- Para UI: "Estado", "Monto Total", etc.

  -- Valores anterior y nuevo
  old_value TEXT,
  new_value TEXT,

  -- Metadata adicional
  change_context JSONB, -- Info adicional: IP, user agent, módulo, etc.

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Índices para performance del change_log
CREATE INDEX idx_change_log_tenant_id ON system.change_log(tenant_id);
CREATE INDEX idx_change_log_record ON system.change_log(table_schema, table_name, record_id);
CREATE INDEX idx_change_log_changed_by ON system.change_log(changed_by);
CREATE INDEX idx_change_log_changed_at ON system.change_log(changed_at DESC);
CREATE INDEX idx_change_log_type ON system.change_log(change_type);

-- Índice compuesto para queries comunes
CREATE INDEX idx_change_log_record_date
ON system.change_log(table_schema, table_name, record_id, changed_at DESC);

-- RLS Policy para multi-tenancy
ALTER TABLE system.change_log ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation_change_log ON system.change_log
  USING (tenant_id = get_current_tenant_id());

-- =====================================================
-- FUNCIÓN DE TRACKING AUTOMÁTICO
-- =====================================================

-- Función: track_field_changes
-- Función genérica para trackear cambios automáticamente
CREATE OR REPLACE FUNCTION system.track_field_changes()
RETURNS TRIGGER AS $$
DECLARE
  v_tenant_id UUID;
  v_user_id UUID;
  v_field_name TEXT;
  v_field_label TEXT;
  v_old_value TEXT;
  v_new_value TEXT;
  v_field_config RECORD;
BEGIN
  -- Obtener tenant_id y user_id del registro
  IF TG_OP = 'DELETE' THEN
    v_tenant_id := OLD.tenant_id;
    v_user_id := OLD.deleted_by;
  ELSE
    v_tenant_id := NEW.tenant_id;
    v_user_id := NEW.updated_by;
  END IF;

  -- Registrar creación
  IF TG_OP = 'INSERT' THEN
    INSERT INTO system.change_log (
      tenant_id, table_schema, table_name, record_id,
      changed_by, change_type, change_context
    ) VALUES (
      v_tenant_id, TG_TABLE_SCHEMA, TG_TABLE_NAME, NEW.id,
      NEW.created_by, 'create',
      jsonb_build_object('operation', 'INSERT')
    );
    RETURN NEW;
  END IF;

  -- Registrar eliminación (soft delete)
  IF TG_OP = 'UPDATE' AND OLD.deleted_at IS NULL AND NEW.deleted_at IS NOT NULL THEN
    INSERT INTO system.change_log (
      tenant_id, table_schema, table_name, record_id,
      changed_by, change_type, change_context
    ) VALUES (
      v_tenant_id, TG_TABLE_SCHEMA, TG_TABLE_NAME, NEW.id,
      NEW.deleted_by, 'delete',
      jsonb_build_object('operation', 'SOFT_DELETE', 'deleted_at', NEW.deleted_at)
    );
    RETURN NEW;
  END IF;

  -- Registrar cambios en campos configurados
  IF TG_OP = 'UPDATE' THEN
    -- Iterar sobre campos configurados para esta tabla
    FOR v_field_config IN
      SELECT field_name, display_label, field_type
      FROM system.field_tracking_config
      WHERE table_schema = TG_TABLE_SCHEMA
        AND table_name = TG_TABLE_NAME
        AND track_changes = true
    LOOP
      v_field_name := v_field_config.field_name;
      v_field_label := v_field_config.display_label;

      -- Obtener valores antiguo y nuevo (usar EXECUTE para campos dinámicos)
      EXECUTE format('SELECT ($1).%I::TEXT, ($2).%I::TEXT', v_field_name, v_field_name)
        INTO v_old_value, v_new_value
        USING OLD, NEW;

      -- Si el valor cambió, registrarlo
      IF v_old_value IS DISTINCT FROM v_new_value THEN
        INSERT INTO system.change_log (
          tenant_id, table_schema, table_name, record_id,
          changed_by, change_type, field_name, field_label,
          old_value, new_value, change_context
        ) VALUES (
          v_tenant_id, TG_TABLE_SCHEMA, TG_TABLE_NAME, NEW.id,
          v_user_id,
          CASE
            WHEN v_field_name = 'status' OR v_field_name = 'state' THEN 'state_change'
            ELSE 'update'
          END,
          v_field_name, v_field_label,
          v_old_value, v_new_value,
          jsonb_build_object('operation', 'UPDATE', 'field_type', v_field_config.field_type)
        );
      END IF;
    END LOOP;
  END IF;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

COMMENT ON FUNCTION system.track_field_changes IS
'Función trigger para trackear cambios automáticamente según configuración en field_tracking_config (patrón mail.thread de Odoo)';

-- =====================================================
-- SEED DATA: Configuración de campos a trackear
-- =====================================================

-- FINANCIAL: Facturas
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('financial', 'invoices', 'status', 'text', 'Estado'),
('financial', 'invoices', 'partner_id', 'uuid', 'Cliente/Proveedor'),
('financial', 'invoices', 'invoice_date', 'timestamp', 'Fecha de Factura'),
('financial', 'invoices', 'amount_total', 'numeric', 'Monto Total'),
('financial', 'invoices', 'payment_term_id', 'uuid', 'Término de Pago')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

-- FINANCIAL: Asientos contables
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('financial', 'journal_entries', 'status', 'text', 'Estado'),
('financial', 'journal_entries', 'date', 'timestamp', 'Fecha del Asiento'),
('financial', 'journal_entries', 'journal_id', 'uuid', 'Diario Contable')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

-- PURCHASE: Órdenes de compra
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('purchase', 'purchase_orders', 'status', 'text', 'Estado'),
('purchase', 'purchase_orders', 'partner_id', 'uuid', 'Proveedor'),
('purchase', 'purchase_orders', 'order_date', 'timestamp', 'Fecha de Orden'),
('purchase', 'purchase_orders', 'amount_total', 'numeric', 'Monto Total'),
('purchase', 'purchase_orders', 'receipt_status', 'text', 'Estado de Recepción')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

-- SALES: Órdenes de venta
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('sales', 'sales_orders', 'status', 'text', 'Estado'),
('sales', 'sales_orders', 'partner_id', 'uuid', 'Cliente'),
('sales', 'sales_orders', 'order_date', 'timestamp', 'Fecha de Orden'),
('sales', 'sales_orders', 'amount_total', 'numeric', 'Monto Total'),
('sales', 'sales_orders', 'invoice_status', 'text', 'Estado de Facturación'),
('sales', 'sales_orders', 'delivery_status', 'text', 'Estado de Entrega')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

-- INVENTORY: Movimientos de stock
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('inventory', 'stock_moves', 'status', 'text', 'Estado'),
('inventory', 'stock_moves', 'product_id', 'uuid', 'Producto'),
('inventory', 'stock_moves', 'product_qty', 'numeric', 'Cantidad'),
('inventory', 'stock_moves', 'location_id', 'uuid', 'Ubicación Origen'),
('inventory', 'stock_moves', 'location_dest_id', 'uuid', 'Ubicación Destino')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

-- PROJECTS: Proyectos
INSERT INTO system.field_tracking_config (table_schema, table_name, field_name, field_type, display_label) VALUES
('projects', 'projects', 'status', 'text', 'Estado'),
('projects', 'projects', 'name', 'text', 'Nombre del Proyecto'),
('projects', 'projects', 'manager_id', 'uuid', 'Responsable'),
('projects', 'projects', 'date_start', 'timestamp', 'Fecha de Inicio'),
('projects', 'projects', 'date_end', 'timestamp', 'Fecha de Fin')
ON CONFLICT (table_schema, table_name, field_name) DO NOTHING;

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

COMMENT ON SCHEMA system IS 'Schema de mensajería, notificaciones, logs, reportes y tracking automático';
COMMENT ON TABLE system.messages IS 'Mensajes del chatter (comentarios, notas, emails)';
COMMENT ON TABLE system.message_followers IS 'Seguidores de registros para notificaciones';
COMMENT ON TABLE system.notifications IS 'Notificaciones a usuarios';
COMMENT ON TABLE system.activities IS 'Actividades programadas (llamadas, reuniones, tareas)';
COMMENT ON TABLE system.message_templates IS 'Plantillas de mensajes y emails';
COMMENT ON TABLE system.email_queue IS 'Cola de envío de emails';
COMMENT ON TABLE system.logs IS 'Logs del sistema y auditoría';
COMMENT ON TABLE system.reports IS 'Definiciones de reportes';
COMMENT ON TABLE system.report_executions IS 'Ejecuciones de reportes con resultados';
COMMENT ON TABLE system.dashboards IS 'Dashboards configurables por usuario';
COMMENT ON TABLE system.dashboard_widgets IS 'Widgets dentro de dashboards';
COMMENT ON TABLE system.field_tracking_config IS 'Configuración de campos a trackear automáticamente por tabla (patrón mail.thread de Odoo)';
COMMENT ON TABLE system.change_log IS 'Historial de cambios en registros (mail.thread pattern de Odoo). Registra automáticamente cambios de estado y campos críticos.';

-- =====================================================
-- FIN DEL SCHEMA SYSTEM
-- =====================================================
