import express from 'express';
const router = express.Router();

// --- Configuration & Helpers ---

const DEFAULT_PAGE_LIMIT = 50;
const MAX_PAGE_LIMIT = 200; // Prevent excessive data requests

// Define direct mapping from frontend column names to database columns
// This simplifies the code by eliminating conversion logic
const COLUMN_MAP = {
    // Product Info
    pid: 'pm.pid',
    sku: 'pm.sku',
    title: 'pm.title',
    brand: 'pm.brand',
    vendor: 'pm.vendor',
    imageUrl: 'pm.image_url',
    isVisible: 'pm.is_visible',
    isReplenishable: 'pm.is_replenishable',
    // Additional Product Fields
    barcode: 'pm.barcode',
    harmonizedTariffCode: 'pm.harmonized_tariff_code',
    vendorReference: 'pm.vendor_reference',
    notionsReference: 'pm.notions_reference',
    line: 'pm.line',
    subline: 'pm.subline',
    artist: 'pm.artist',
    moq: 'pm.moq',
    rating: 'pm.rating',
    reviews: 'pm.reviews',
    weight: 'pm.weight',
    length: 'pm.length',
    width: 'pm.width',
    height: 'pm.height',
    countryOfOrigin: 'pm.country_of_origin',
    location: 'pm.location',
    baskets: 'pm.baskets',
    notifies: 'pm.notifies',
    preorderCount: 'pm.preorder_count',
    notionsInvCount: 'pm.notions_inv_count',
    // Current Status
    currentPrice: 'pm.current_price',
    currentRegularPrice: 'pm.current_regular_price',
    currentCostPrice: 'pm.current_cost_price',
    currentStock: 'pm.current_stock',
    currentStockCost: 'pm.current_stock_cost',
    currentStockRetail: 'pm.current_stock_retail',
    currentStockGross: 'pm.current_stock_gross',
    onOrderQty: 'pm.on_order_qty',
    onOrderCost: 'pm.on_order_cost',
    onOrderRetail: 'pm.on_order_retail',
    earliestExpectedDate: 'pm.earliest_expected_date',
    // Historical Dates
    dateCreated: 'pm.date_created',
    dateFirstReceived: 'pm.date_first_received',
    dateLastReceived: 'pm.date_last_received',
    dateFirstSold: 'pm.date_first_sold',
    dateLastSold: 'pm.date_last_sold',
    ageDays: 'pm.age_days',
    // Rolling Period Metrics
    sales7d: 'pm.sales_7d', 
    revenue7d: 'pm.revenue_7d',
    sales14d: 'pm.sales_14d', 
    revenue14d: 'pm.revenue_14d',
    sales30d: 'pm.sales_30d', 
    revenue30d: 'pm.revenue_30d',
    cogs30d: 'pm.cogs_30d', 
    profit30d: 'pm.profit_30d',
    returnsUnits30d: 'pm.returns_units_30d', 
    returnsRevenue30d: 'pm.returns_revenue_30d',
    discounts30d: 'pm.discounts_30d', 
    grossRevenue30d: 'pm.gross_revenue_30d',
    grossRegularRevenue30d: 'pm.gross_regular_revenue_30d',
    stockoutDays30d: 'pm.stockout_days_30d',
    sales365d: 'pm.sales_365d', 
    revenue365d: 'pm.revenue_365d',
    avgStockUnits30d: 'pm.avg_stock_units_30d', 
    avgStockCost30d: 'pm.avg_stock_cost_30d',
    avgStockRetail30d: 'pm.avg_stock_retail_30d', 
    avgStockGross30d: 'pm.avg_stock_gross_30d',
    receivedQty30d: 'pm.received_qty_30d', 
    receivedCost30d: 'pm.received_cost_30d',
    // Lifetime Metrics
    lifetimeSales: 'pm.lifetime_sales', 
    lifetimeRevenue: 'pm.lifetime_revenue',
    // First Period Metrics
    first7DaysSales: 'pm.first_7_days_sales', 
    first7DaysRevenue: 'pm.first_7_days_revenue',
    first30DaysSales: 'pm.first_30_days_sales', 
    first30DaysRevenue: 'pm.first_30_days_revenue',
    first60DaysSales: 'pm.first_60_days_sales', 
    first60DaysRevenue: 'pm.first_60_days_revenue',
    first90DaysSales: 'pm.first_90_days_sales', 
    first90DaysRevenue: 'pm.first_90_days_revenue',
    // Calculated KPIs
    asp30d: 'pm.asp_30d', 
    acp30d: 'pm.acp_30d', 
    avgRos30d: 'pm.avg_ros_30d',
    avgSalesPerDay30d: 'pm.avg_sales_per_day_30d', 
    avgSalesPerMonth30d: 'pm.avg_sales_per_month_30d',
    margin30d: 'pm.margin_30d', 
    markup30d: 'pm.markup_30d', 
    gmroi30d: 'pm.gmroi_30d',
    stockturn30d: 'pm.stockturn_30d', 
    returnRate30d: 'pm.return_rate_30d',
    discountRate30d: 'pm.discount_rate_30d', 
    stockoutRate30d: 'pm.stockout_rate_30d',
    markdown30d: 'pm.markdown_30d', 
    markdownRate30d: 'pm.markdown_rate_30d',
    sellThrough30d: 'pm.sell_through_30d', 
    avgLeadTimeDays: 'pm.avg_lead_time_days',
    // Forecasting & Replenishment
    abcClass: 'pm.abc_class', 
    salesVelocityDaily: 'pm.sales_velocity_daily',
    configLeadTime: 'pm.config_lead_time', 
    configDaysOfStock: 'pm.config_days_of_stock',
    configSafetyStock: 'pm.config_safety_stock', 
    planningPeriodDays: 'pm.planning_period_days',
    leadTimeForecastUnits: 'pm.lead_time_forecast_units', 
    daysOfStockForecastUnits: 'pm.days_of_stock_forecast_units',
    planningPeriodForecastUnits: 'pm.planning_period_forecast_units', 
    leadTimeClosingStock: 'pm.lead_time_closing_stock',
    daysOfStockClosingStock: 'pm.days_of_stock_closing_stock', 
    replenishmentNeededRaw: 'pm.replenishment_needed_raw',
    replenishmentUnits: 'pm.replenishment_units', 
    replenishmentCost: 'pm.replenishment_cost',
    replenishmentRetail: 'pm.replenishment_retail', 
    replenishmentProfit: 'pm.replenishment_profit',
    toOrderUnits: 'pm.to_order_units', 
    forecastLostSalesUnits: 'pm.forecast_lost_sales_units',
    forecastLostRevenue: 'pm.forecast_lost_revenue', 
    stockCoverInDays: 'pm.stock_cover_in_days',
    poCoverInDays: 'pm.po_cover_in_days', 
    sellsOutInDays: 'pm.sells_out_in_days',
    replenishDate: 'pm.replenish_date', 
    overstockedUnits: 'pm.overstocked_units',
    overstockedCost: 'pm.overstocked_cost', 
    overstockedRetail: 'pm.overstocked_retail',
    isOldStock: 'pm.is_old_stock',
    // Yesterday
    yesterdaySales: 'pm.yesterday_sales',
    // Map status column - directly mapped now instead of calculated on frontend
    status: 'pm.status',
    
    // Growth Metrics (P3)
    salesGrowth30dVsPrev: 'pm.sales_growth_30d_vs_prev',
    revenueGrowth30dVsPrev: 'pm.revenue_growth_30d_vs_prev',
    salesGrowthYoy: 'pm.sales_growth_yoy',
    revenueGrowthYoy: 'pm.revenue_growth_yoy',
    
    // Demand Variability Metrics (P3)
    salesVariance30d: 'pm.sales_variance_30d',
    salesStdDev30d: 'pm.sales_std_dev_30d',
    salesCv30d: 'pm.sales_cv_30d',
    demandPattern: 'pm.demand_pattern',
    
    // Service Level Metrics (P5)
    fillRate30d: 'pm.fill_rate_30d',
    stockoutIncidents30d: 'pm.stockout_incidents_30d',
    serviceLevel30d: 'pm.service_level_30d',
    lostSalesIncidents30d: 'pm.lost_sales_incidents_30d',
    
    // Seasonality Metrics (P5) 
    seasonalityIndex: 'pm.seasonality_index',
    seasonalPattern: 'pm.seasonal_pattern',
    peakSeason: 'pm.peak_season',
    
    // Lifetime Revenue Quality
    lifetimeRevenueQuality: 'pm.lifetime_revenue_quality'
};

// Define column types for use in sorting/filtering
// This helps apply correct comparison operators and sorting logic
const COLUMN_TYPES = {
    // Numeric columns (use numeric operators and sorting)
    numeric: [
        'pid', 'currentPrice', 'currentRegularPrice', 'currentCostPrice',
        'currentStock', 'currentStockCost', 'currentStockRetail', 'currentStockGross',
        'onOrderQty', 'onOrderCost', 'onOrderRetail', 'ageDays',
        'sales7d', 'revenue7d', 'sales14d', 'revenue14d', 'sales30d', 'revenue30d',
        'cogs30d', 'profit30d', 'returnsUnits30d', 'returnsRevenue30d', 'discounts30d',
        'grossRevenue30d', 'grossRegularRevenue30d', 'stockoutDays30d', 'sales365d', 'revenue365d',
        'avgStockUnits30d', 'avgStockCost30d', 'avgStockRetail30d', 'avgStockGross30d',
        'receivedQty30d', 'receivedCost30d', 'lifetimeSales', 'lifetimeRevenue',
        'first7DaysSales', 'first7DaysRevenue', 'first30DaysSales', 'first30DaysRevenue',
        'first60DaysSales', 'first60DaysRevenue', 'first90DaysSales', 'first90DaysRevenue',
        'asp30d', 'acp30d', 'avgRos30d', 'avgSalesPerDay30d', 'avgSalesPerMonth30d',
        'margin30d', 'markup30d', 'gmroi30d', 'stockturn30d', 'returnRate30d', 'discountRate30d',
        'stockoutRate30d', 'markdown30d', 'markdownRate30d', 'sellThrough30d', 'avgLeadTimeDays',
        'salesVelocityDaily', 'configLeadTime', 'configDaysOfStock', 'configSafetyStock',
        'planningPeriodDays', 'leadTimeForecastUnits', 'daysOfStockForecastUnits',
        'planningPeriodForecastUnits', 'leadTimeClosingStock', 'daysOfStockClosingStock',
        'replenishmentNeededRaw', 'replenishmentUnits', 'replenishmentCost', 'replenishmentRetail',
        'replenishmentProfit', 'toOrderUnits', 'forecastLostSalesUnits', 'forecastLostRevenue',
        'stockCoverInDays', 'poCoverInDays', 'sellsOutInDays', 'overstockedUnits',
        'overstockedCost', 'overstockedRetail', 'yesterdaySales',
        // New numeric columns
        'moq', 'rating', 'reviews', 'weight', 'length', 'width', 'height', 
        'baskets', 'notifies', 'preorderCount', 'notionsInvCount',
        // Growth metrics
        'salesGrowth30dVsPrev', 'revenueGrowth30dVsPrev', 'salesGrowthYoy', 'revenueGrowthYoy',
        // Demand variability metrics
        'salesVariance30d', 'salesStdDev30d', 'salesCv30d',
        // Service level metrics
        'fillRate30d', 'stockoutIncidents30d', 'serviceLevel30d', 'lostSalesIncidents30d',
        // Seasonality metrics
        'seasonalityIndex'
    ],
    // Date columns (use date operators and sorting)
    date: [
        'dateCreated', 'dateFirstReceived', 'dateLastReceived', 'dateFirstSold', 'dateLastSold',
        'earliestExpectedDate', 'replenishDate', 'forecastedOutOfStockDate'
    ],
    // String columns (use string operators and sorting)
    string: [
        'sku', 'title', 'brand', 'vendor', 'imageUrl', 'abcClass', 'status',
        // New string columns
        'barcode', 'harmonizedTariffCode', 'vendorReference', 'notionsReference',
        'line', 'subline', 'artist', 'countryOfOrigin', 'location',
        // New string columns for patterns
        'demandPattern', 'seasonalPattern', 'peakSeason', 'lifetimeRevenueQuality'
    ],
    // Boolean columns (use boolean operators and sorting)
    boolean: ['isVisible', 'isReplenishable', 'isOldStock']
};

// Special sort handling for certain columns
const SPECIAL_SORT_COLUMNS = {
    // Percentage columns where we want to sort by the numeric value
    margin30d: true,
    markup30d: true,
    sellThrough30d: true,
    discountRate30d: true,
    stockoutRate30d: true,
    returnRate30d: true,
    markdownRate30d: true,
    
    // Columns where we may want to sort by absolute value
    profit30d: 'abs',
    
    // Velocity columns
    salesVelocityDaily: true,
    
    // Growth rate columns
    salesGrowth30dVsPrev: 'abs',
    revenueGrowth30dVsPrev: 'abs',
    salesGrowthYoy: 'abs',
    revenueGrowthYoy: 'abs',
    
    // Status column needs special ordering
    status: 'priority'
};

// Status priority for sorting (lower number = higher priority)
// Values must match what's stored in the DB status column
const STATUS_PRIORITY = {
    'Critical': 1,
    'At Risk': 2,
    'Reorder Soon': 3,
    'Overstock': 4,
    'Healthy': 5,
    'New': 6
};

// Get database column name from frontend column name
// Returns null for unknown keys so callers can skip them
function getDbColumn(frontendColumn) {
    return COLUMN_MAP[frontendColumn] || null;
}

// Get column type by searching through the COLUMN_TYPES arrays
function getColumnType(frontendColumn) {
    if (COLUMN_TYPES.numeric.includes(frontendColumn)) return 'numeric';
    if (COLUMN_TYPES.date.includes(frontendColumn)) return 'date';
    if (COLUMN_TYPES.boolean.includes(frontendColumn)) return 'boolean';
    return 'string';
}

// --- Route Handlers ---

// GET /metrics/summary - Aggregate KPI summary for the current view
router.get('/summary', async (req, res) => {
    const pool = req.app.locals.pool;

    try {
        // Build WHERE clause from same filters as main list endpoint
        const conditions = ['pm.is_visible = true', 'pm.is_replenishable = true'];
        const params = [];
        let paramCounter = 1;

        // Handle showNonReplenishable
        if (req.query.showNonReplenishable === 'true') {
            // Remove the is_replenishable condition
            conditions.pop();
        }
        // Handle showInvisible
        if (req.query.showInvisible === 'true') {
            conditions.shift(); // Remove is_visible condition
        }

        // Handle stock_status filter
        if (req.query.stock_status) {
            conditions.push(`pm.status = $${paramCounter++}`);
            params.push(req.query.stock_status);
        }

        const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

        const sql = `
            SELECT
                COUNT(*)::int AS total_products,
                COALESCE(SUM(pm.current_stock_cost), 0)::numeric(15,2) AS total_stock_value,
                COALESCE(SUM(pm.current_stock_retail), 0)::numeric(15,2) AS total_stock_retail,
                COUNT(*) FILTER (WHERE pm.status IN ('Critical', 'Reorder Soon'))::int AS needs_reorder_count,
                COALESCE(SUM(pm.replenishment_cost) FILTER (WHERE pm.replenishment_units > 0), 0)::numeric(15,2) AS total_replenishment_cost,
                COALESCE(SUM(pm.replenishment_units) FILTER (WHERE pm.replenishment_units > 0), 0)::int AS total_replenishment_units,
                COALESCE(SUM(pm.overstocked_cost) FILTER (WHERE pm.overstocked_units > 0), 0)::numeric(15,2) AS total_overstock_value,
                COALESCE(SUM(pm.overstocked_units) FILTER (WHERE pm.overstocked_units > 0), 0)::int AS total_overstock_units,
                COALESCE(SUM(pm.on_order_qty), 0)::int AS total_on_order_units,
                COALESCE(SUM(pm.on_order_cost), 0)::numeric(15,2) AS total_on_order_cost,
                COALESCE(AVG(pm.stock_cover_in_days) FILTER (WHERE pm.stock_cover_in_days IS NOT NULL AND pm.current_stock > 0), 0)::numeric(10,1) AS avg_stock_cover_days,
                COUNT(*) FILTER (WHERE pm.current_stock = 0)::int AS out_of_stock_count,
                COALESCE(SUM(pm.forecast_lost_revenue) FILTER (WHERE pm.forecast_lost_revenue > 0), 0)::numeric(15,2) AS total_lost_revenue,
                COALESCE(SUM(pm.forecast_lost_sales_units) FILTER (WHERE pm.forecast_lost_sales_units > 0), 0)::int AS total_lost_sales_units,
                COUNT(*) FILTER (WHERE pm.status = 'Critical')::int AS critical_count,
                COUNT(*) FILTER (WHERE pm.status = 'Reorder Soon')::int AS reorder_count,
                COUNT(*) FILTER (WHERE pm.status = 'At Risk')::int AS at_risk_count,
                COUNT(*) FILTER (WHERE pm.status = 'Overstock')::int AS overstock_count,
                COUNT(*) FILTER (WHERE pm.status = 'Healthy')::int AS healthy_count,
                COUNT(*) FILTER (WHERE pm.status = 'New')::int AS new_count
            FROM public.product_metrics pm
            ${whereClause}
        `;

        const { rows } = await pool.query(sql, params);
        res.json(rows[0]);

    } catch (error) {
        console.error('Error fetching metrics summary:', error);
        res.status(500).json({ error: 'Failed to fetch metrics summary.' });
    }
});

// GET /metrics/filter-options - Provide distinct values for filter dropdowns
router.get('/filter-options', async (req, res) => {
    const pool = req.app.locals.pool;
    try {
        const [vendorRes, brandRes, abcClassRes] = await Promise.all([
            pool.query(`SELECT DISTINCT vendor FROM public.product_metrics WHERE vendor IS NOT NULL AND vendor <> '' ORDER BY vendor`),
            pool.query(`SELECT DISTINCT COALESCE(brand, 'Unbranded') as brand FROM public.product_metrics WHERE brand IS NOT NULL AND brand <> '' ORDER BY brand`),
            pool.query(`SELECT DISTINCT abc_class FROM public.product_metrics WHERE abc_class IS NOT NULL ORDER BY abc_class`)
            // Add queries for other distinct options if needed (e.g., categories if stored on pm)
        ]);

        res.json({
            vendors: vendorRes.rows.map(r => r.vendor),
            brands: brandRes.rows.map(r => r.brand),
            abcClasses: abcClassRes.rows.map(r => r.abc_class),
        });
    } catch (error) {
        console.error('Error fetching filter options:', error);
        res.status(500).json({ error: 'Failed to fetch filter options' });
    }
});


// GET /metrics/ - List all product metrics with filtering, sorting, pagination
router.get('/', async (req, res) => {
    const pool = req.app.locals.pool;

    try {
        // --- Pagination ---
        let page = parseInt(req.query.page, 10);
        let limit = parseInt(req.query.limit, 10);
        if (isNaN(page) || page < 1) page = 1;
        if (isNaN(limit) || limit < 1) limit = DEFAULT_PAGE_LIMIT;
        limit = Math.min(limit, MAX_PAGE_LIMIT); // Cap the limit
        const offset = (page - 1) * limit;

        // --- Sorting ---
        const sortQueryKey = req.query.sort || 'title'; // Default sort field key
        const sortDbColumn = getDbColumn(sortQueryKey) || 'pm.title';
        const columnType = getColumnType(sortQueryKey);
        
        const sortDirection = req.query.order?.toLowerCase() === 'desc' ? 'DESC' : 'ASC';

        // Always put nulls last regardless of sort direction or column type
        const nullsOrder = 'NULLS LAST';

        // Build the ORDER BY clause based on column type and special handling
        let orderByClause;

        if (SPECIAL_SORT_COLUMNS[sortQueryKey] === 'abs') {
            // Sort by absolute value for columns where negative values matter
            orderByClause = `ABS(${sortDbColumn}::numeric) ${sortDirection} ${nullsOrder}`;
        } else if (columnType === 'numeric' || SPECIAL_SORT_COLUMNS[sortQueryKey] === true) {
            // For numeric columns, cast to numeric to ensure proper sorting
            orderByClause = `${sortDbColumn}::numeric ${sortDirection} ${nullsOrder}`;
        } else if (columnType === 'date') {
            // For date columns, cast to timestamp to ensure proper sorting
            orderByClause = `CASE WHEN ${sortDbColumn} IS NULL THEN 1 ELSE 0 END, ${sortDbColumn}::timestamp ${sortDirection}`;
        } else if (SPECIAL_SORT_COLUMNS[sortQueryKey] === 'priority') {
            // Special handling for status column, using priority for known statuses
            orderByClause = `
                CASE WHEN ${sortDbColumn} IS NULL THEN 999
                     WHEN ${sortDbColumn} = 'Critical' THEN 1
                     WHEN ${sortDbColumn} = 'At Risk' THEN 2
                     WHEN ${sortDbColumn} = 'Reorder Soon' THEN 3
                     WHEN ${sortDbColumn} = 'Overstock' THEN 4
                     WHEN ${sortDbColumn} = 'Healthy' THEN 5
                     WHEN ${sortDbColumn} = 'New' THEN 6
                     ELSE 100
                END ${sortDirection} ${nullsOrder},
                ${sortDbColumn} ${sortDirection}`;
        } else {
            // For string and boolean columns, no special casting needed
            orderByClause = `CASE WHEN ${sortDbColumn} IS NULL THEN 1 ELSE 0 END, ${sortDbColumn} ${sortDirection}`;
        }

        // --- Filtering ---
        const conditions = [];
        const params = [];
        let paramCounter = 1;

        // Add default visibility/replenishable filters unless overridden
        if (req.query.showInvisible !== 'true') conditions.push(`pm.is_visible = true`);
        if (req.query.showNonReplenishable !== 'true') conditions.push(`pm.is_replenishable = true`);

        // Special handling for stock_status
        if (req.query.stock_status) {
            const status = req.query.stock_status;
            // Handle special case for "at-risk" which is stored as "At Risk" in the database
            if (status.toLowerCase() === 'at-risk') {
                conditions.push(`pm.status = $${paramCounter++}`);
                params.push('At Risk');
            } else {
                // Capitalize first letter to match database values
                conditions.push(`pm.status = $${paramCounter++}`);
                params.push(status.charAt(0).toUpperCase() + status.slice(1));
            }
        }

        // Process other filters from query parameters
        for (const key in req.query) {
            // Skip control params
            if (['page', 'limit', 'sort', 'order', 'showInvisible', 'showNonReplenishable', 'stock_status'].includes(key)) continue;

            let filterKey = key;
            let operator = '='; // Default operator
            let value = req.query[key];

            // Check for operator suffixes (e.g., sales30d_gt, title_ilike, isVisible_is_true)
            const operatorMatch = key.match(/^(.*)_(eq|ne|gt|gte|lt|lte|like|ilike|starts_with|ends_with|not_contains|between|in|is_empty|is_not_empty|is_true|is_false)$/);
            if (operatorMatch) {
                filterKey = operatorMatch[1]; // e.g., "sales30d"
                operator = operatorMatch[2]; // e.g., "gt"
            }

            // Get the database column for this filter key
            const filterDbColumn = getDbColumn(filterKey);
            const valueType = getColumnType(filterKey);

            if (!filterDbColumn) {
                console.warn(`Invalid filter key ignored: ${key}`);
                continue; // Skip if the key doesn't map to a known column
            }

            // --- Build WHERE clause fragment ---
            let needsParam = true; // Declared outside try so catch can access it
            try {
                let conditionFragment = '';

                switch (operator.toLowerCase()) {
                    case 'eq': operator = '='; break;
                    case 'ne': operator = '<>'; break;
                    case 'gt': operator = '>'; break;
                    case 'gte': operator = '>='; break;
                    case 'lt': operator = '<'; break;
                    case 'lte': operator = '<='; break;
                    case 'like': operator = 'ILIKE'; value = `%${value}%`; break;
                    case 'ilike': operator = 'ILIKE'; value = `%${value}%`; break;
                    case 'starts_with': operator = 'ILIKE'; value = `${value}%`; break;
                    case 'ends_with': operator = 'ILIKE'; value = `%${value}`; break;
                    case 'not_contains': operator = 'NOT ILIKE'; value = `%${value}%`; break;
                    case 'is_empty':
                        conditionFragment = `(${filterDbColumn} IS NULL OR ${filterDbColumn}::text = '')`;
                        needsParam = false;
                        break;
                    case 'is_not_empty':
                        conditionFragment = `(${filterDbColumn} IS NOT NULL AND ${filterDbColumn}::text <> '')`;
                        needsParam = false;
                        break;
                    case 'is_true':
                        conditionFragment = `${filterDbColumn} = true`;
                        needsParam = false;
                        break;
                    case 'is_false':
                        conditionFragment = `${filterDbColumn} = false`;
                        needsParam = false;
                        break;
                    case 'between':
                        const [val1, val2] = String(value).split(',');
                        if (val1 !== undefined && val2 !== undefined) {
                             conditionFragment = `${filterDbColumn} BETWEEN $${paramCounter++} AND $${paramCounter++}`;
                             params.push(parseValue(val1, valueType), parseValue(val2, valueType));
                             needsParam = false;
                        } else {
                             console.warn(`Invalid 'between' value for ${key}: ${value}`);
                             continue;
                        }
                        break;
                    case 'in':
                        const inValues = String(value).split(',');
                        if (inValues.length > 0) {
                            const placeholders = inValues.map(() => `$${paramCounter++}`).join(', ');
                            conditionFragment = `${filterDbColumn} IN (${placeholders})`;
                            params.push(...inValues.map(v => parseValue(v, valueType)));
                            needsParam = false;
                        } else {
                             console.warn(`Invalid 'in' value for ${key}: ${value}`);
                             continue;
                        }
                        break;
                    case '=':
                    default: operator = '='; break;
                }

                if (needsParam) {
                    conditionFragment = `${filterDbColumn} ${operator} $${paramCounter++}`;
                    params.push(parseValue(value, valueType));
                }

                if (conditionFragment) {
                    conditions.push(`(${conditionFragment})`);
                }

            } catch (parseError) {
                 console.warn(`Skipping filter for key "${key}" due to parsing error: ${parseError.message}`);
                 if (needsParam) paramCounter--;
            }
        }

        // --- Construct and Execute Queries ---
        const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

        // Count Query
        const countSql = `SELECT COUNT(*) AS total FROM public.product_metrics pm ${whereClause}`;
        const countPromise = pool.query(countSql, params);

        // Data Query (Select all columns from metrics table for now)
        const dataSql = `
            SELECT pm.*
            FROM public.product_metrics pm
            ${whereClause}
            ORDER BY ${orderByClause}
            LIMIT $${paramCounter} OFFSET $${paramCounter + 1}
        `;
        const dataParams = [...params, limit, offset];
        const dataPromise = pool.query(dataSql, dataParams);

        // Execute queries in parallel
        const [countResult, dataResult] = await Promise.all([countPromise, dataPromise]);

        const total = parseInt(countResult.rows[0].total, 10);
        const metrics = dataResult.rows;

        // --- Respond ---
        res.json({
            metrics,
            pagination: {
                total,
                pages: Math.ceil(total / limit),
                currentPage: page,
                limit,
            },
            // Optionally include applied filters/sort for frontend confirmation
             appliedQuery: {
                 filters: req.query, // Send back raw query filters
                 sort: sortQueryKey,
                 order: sortDirection.toLowerCase()
             }
        });

    } catch (error) {
        console.error('Error fetching metrics list:', error);
        res.status(500).json({ error: 'Failed to fetch product metrics list.' });
    }
});

// GET /metrics/:pid - Get metrics for a single product
router.get('/:pid', async (req, res) => {
    const pool = req.app.locals.pool;
    const pid = parseInt(req.params.pid, 10);

    if (isNaN(pid)) {
        return res.status(400).json({ error: 'Invalid Product ID.' });
    }

    try {
        const { rows } = await pool.query(
            `SELECT * FROM public.product_metrics WHERE pid = $1`,
            [pid]
        );

        if (rows.length === 0) {
            return res.status(404).json({ error: 'Metrics not found for this product.' });
        }
        // Data is pre-calculated, return the first (only) row
        res.json(rows[0]);

    } catch (error) {
        console.error(`Error fetching metrics for PID ${pid}:`, error);
        res.status(500).json({ error: 'Failed to fetch product metrics.' });
    }
});


/**
 * Parses a value based on its expected type.
 * Throws error for invalid formats.
 */
function parseValue(value, type) {
    if (value === null || value === undefined || value === '') return null; // Allow empty strings? Or handle differently?

    switch (type) {
        case 'numeric':
            const num = parseFloat(value);
            if (isNaN(num)) throw new Error(`Invalid number format: "${value}"`);
            return num;
        case 'boolean':
            if (String(value).toLowerCase() === 'true') return true;
            if (String(value).toLowerCase() === 'false') return false;
            throw new Error(`Invalid boolean format: "${value}"`);
        case 'date':
            // Basic validation, rely on DB to handle actual date conversion
            if (!String(value).match(/^\d{4}-\d{2}-\d{2}$/)) {
               // Allow full timestamps too? Adjust regex if needed
               // console.warn(`Potentially invalid date format: "${value}"`); // Warn instead of throwing?
            }
            return String(value); // Send as string, let DB handle it
        case 'string':
        default:
            return String(value);
    }
}

export default router;