-- =============================================================================
-- MICHANGARRITO - 21 ANALYTICS (MCH-034, MCH-035: Analytics y Reportes)
-- =============================================================================
-- Sistema de metricas, analytics y generacion de reportes
-- Almacena metricas agregadas y permite exportacion de reportes
-- =============================================================================

-- Tipos de metrica
CREATE TYPE metric_type AS ENUM (
    -- Ventas
    'sales_total',
    'sales_count',
    'sales_average_ticket',
    'sales_by_category',
    'sales_by_payment_method',

    -- Clientes
    'customers_total',
    'customers_new',
    'customers_active',
    'customers_retention_rate',

    -- Fiados
    'credits_total_amount',
    'credits_pending_amount',
    'credits_overdue_amount',
    'credits_recovery_rate',

    -- Inventario
    'inventory_total_value',
    'inventory_low_stock_count',
    'inventory_turnover_rate',

    -- Productos
    'products_total',
    'products_top_selling',
    'products_slow_moving'
);

-- Tipos de periodo
CREATE TYPE metric_period AS ENUM (
    'hourly',
    'daily',
    'weekly',
    'monthly',
    'yearly'
);

-- Metricas agregadas (pre-calculadas)
CREATE TABLE IF NOT EXISTS analytics.metrics (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,

    -- Tipo y periodo
    metric_type metric_type NOT NULL,
    period_type metric_period NOT NULL,
    period_start TIMESTAMPTZ NOT NULL,
    period_end TIMESTAMPTZ NOT NULL,

    -- Valor
    value DECIMAL(15, 2) NOT NULL,

    -- Metadata adicional (desglose, comparacion, etc.)
    metadata JSONB DEFAULT '{}',

    -- Timestamp
    created_at TIMESTAMPTZ DEFAULT NOW(),

    -- Constraint: una metrica por tenant/tipo/periodo
    UNIQUE(tenant_id, metric_type, period_type, period_start)
);

CREATE INDEX idx_analytics_metrics_tenant ON analytics.metrics(tenant_id);
CREATE INDEX idx_analytics_metrics_type ON analytics.metrics(metric_type);
CREATE INDEX idx_analytics_metrics_period ON analytics.metrics(period_start DESC);
CREATE INDEX idx_analytics_metrics_lookup ON analytics.metrics(tenant_id, metric_type, period_type, period_start DESC);

COMMENT ON TABLE analytics.metrics IS 'Metricas pre-calculadas para dashboards';
COMMENT ON COLUMN analytics.metrics.metadata IS 'Desglose adicional: {by_category: {...}, comparison: {...}}';

-- Eventos de analytics (tracking en tiempo real)
CREATE TABLE IF NOT EXISTS analytics.events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,

    -- Evento
    event_type VARCHAR(100) NOT NULL,
    event_name VARCHAR(255),

    -- Propiedades
    properties JSONB DEFAULT '{}',

    -- Contexto
    user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
    session_id VARCHAR(100),

    -- Timestamp
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_analytics_events_tenant ON analytics.events(tenant_id);
CREATE INDEX idx_analytics_events_type ON analytics.events(event_type);
CREATE INDEX idx_analytics_events_created ON analytics.events(created_at DESC);

-- Particionado por fecha (para performance en grandes volumenes)
-- En produccion considerar particionado real
-- Usa funcion IMMUTABLE timestamptz_to_date() definida en 02-functions.sql
CREATE INDEX idx_analytics_events_date ON analytics.events(public.timestamptz_to_date(created_at));

COMMENT ON TABLE analytics.events IS 'Eventos de tracking para analytics detallado';

-- Tipos de reporte
CREATE TYPE report_type AS ENUM (
    -- Ventas
    'sales_summary',
    'sales_detail',
    'sales_by_product',
    'sales_by_category',
    'sales_by_period',

    -- Inventario
    'inventory_status',
    'inventory_movements',
    'inventory_valuation',

    -- Clientes
    'customers_list',
    'customers_top',
    'customers_inactive',

    -- Fiados
    'credits_pending',
    'credits_overdue',
    'credits_history',

    -- Financiero
    'cash_flow',
    'profit_loss',

    -- Operativo
    'corte_caja'
);

-- Formato de exportacion
CREATE TYPE report_format AS ENUM (
    'pdf',
    'xlsx',
    'csv',
    'json'
);

-- Estado del reporte
CREATE TYPE report_status AS ENUM (
    'pending',
    'processing',
    'completed',
    'failed',
    'expired'
);

-- Reportes generados
CREATE TABLE IF NOT EXISTS analytics.reports (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,

    -- Tipo y nombre
    report_type report_type NOT NULL,
    name VARCHAR(255) NOT NULL,

    -- Parametros del reporte
    parameters JSONB DEFAULT '{}',
    -- Ejemplo: {date_from, date_to, category_id, include_details}

    -- Resultado
    status report_status DEFAULT 'pending',
    file_format report_format,
    file_url TEXT,  -- URL firmada de storage
    file_size INTEGER,  -- bytes

    -- Errores
    error_message TEXT,

    -- Solicitante
    requested_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT NOW(),
    started_at TIMESTAMPTZ,
    completed_at TIMESTAMPTZ,
    expires_at TIMESTAMPTZ  -- Cuando expira el archivo
);

CREATE INDEX idx_analytics_reports_tenant ON analytics.reports(tenant_id);
CREATE INDEX idx_analytics_reports_status ON analytics.reports(status);
CREATE INDEX idx_analytics_reports_type ON analytics.reports(report_type);
CREATE INDEX idx_analytics_reports_created ON analytics.reports(created_at DESC);

COMMENT ON TABLE analytics.reports IS 'Reportes generados para exportacion';
COMMENT ON COLUMN analytics.reports.parameters IS 'Parametros usados para generar el reporte';
COMMENT ON COLUMN analytics.reports.expires_at IS 'Fecha de expiracion del archivo (auto-limpieza)';

-- Programacion de reportes (reportes automaticos)
CREATE TABLE IF NOT EXISTS analytics.report_schedules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,

    -- Configuracion
    name VARCHAR(255) NOT NULL,
    report_type report_type NOT NULL,
    file_format report_format DEFAULT 'pdf',
    parameters JSONB DEFAULT '{}',

    -- Programacion (cron-like)
    schedule_type VARCHAR(20) NOT NULL,  -- 'daily', 'weekly', 'monthly'
    schedule_day INTEGER,  -- 1-7 para weekly, 1-31 para monthly
    schedule_hour INTEGER DEFAULT 8,  -- Hora del dia (0-23)
    timezone VARCHAR(50) DEFAULT 'America/Mexico_City',

    -- Entrega
    delivery_email VARCHAR(255),  -- Email para enviar reporte
    delivery_webhook_url TEXT,    -- Webhook para notificar

    -- Estado
    is_active BOOLEAN DEFAULT true,
    last_run_at TIMESTAMPTZ,
    next_run_at TIMESTAMPTZ,

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_analytics_schedules_tenant ON analytics.report_schedules(tenant_id);
CREATE INDEX idx_analytics_schedules_next_run ON analytics.report_schedules(next_run_at) WHERE is_active = true;

CREATE TRIGGER update_analytics_report_schedules_updated_at
    BEFORE UPDATE ON analytics.report_schedules
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

COMMENT ON TABLE analytics.report_schedules IS 'Programacion de reportes automaticos';

-- =============================================================================
-- FUNCIONES DE ANALYTICS
-- =============================================================================

-- Funcion para obtener metricas de un periodo
CREATE OR REPLACE FUNCTION analytics.get_metrics(
    p_tenant_id UUID,
    p_metric_type metric_type,
    p_period_type metric_period,
    p_start_date TIMESTAMPTZ,
    p_end_date TIMESTAMPTZ
) RETURNS TABLE (
    period_start TIMESTAMPTZ,
    value DECIMAL(15, 2),
    metadata JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT m.period_start, m.value, m.metadata
    FROM analytics.metrics m
    WHERE m.tenant_id = p_tenant_id
      AND m.metric_type = p_metric_type
      AND m.period_type = p_period_type
      AND m.period_start >= p_start_date
      AND m.period_start < p_end_date
    ORDER BY m.period_start;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION analytics.get_metrics IS 'Obtiene metricas de un periodo especifico';

-- Funcion para limpiar reportes expirados
CREATE OR REPLACE FUNCTION analytics.cleanup_expired_reports()
RETURNS INTEGER AS $$
DECLARE
    v_deleted INTEGER;
BEGIN
    WITH deleted AS (
        DELETE FROM analytics.reports
        WHERE expires_at < NOW()
          AND status = 'completed'
        RETURNING id
    )
    SELECT COUNT(*) INTO v_deleted FROM deleted;

    RETURN v_deleted;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION analytics.cleanup_expired_reports IS 'Elimina reportes expirados';
