import express from 'express';
import { businessTodayStr, businessDateOf, businessNow, formatDateCol } from '../../shared/business-time/index.js';
const router = express.Router();

// Forecasting: summarize sales for products received in a period by brand
router.get('/forecast', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const brand = (req.query.brand || '').toString();
    const titleSearch = (req.query.search || req.query.q || '').toString().trim() || null;
    const startDateStr = req.query.startDate;
    const endDateStr = req.query.endDate;

    if (!brand) {
      return res.status(400).json({ error: 'Missing required parameter: brand' });
    }

    // Default to last 30 business days if no dates provided. Params are
    // date-only business dates ('YYYY-MM-DD'); instants are converted.
    const endISO = endDateStr ? businessDateOf(endDateStr) : businessTodayStr();
    const startISO = startDateStr
      ? businessDateOf(startDateStr)
      : new Date(Date.parse(endISO) - 29 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);

    const sql = `
      WITH params AS (
        SELECT
          $1::date AS start_date,
          $2::date AS end_date,
          $3::text AS brand,
          $4::text AS title_search,
          (($2::date - $1::date) + 1)::int AS days
      ),
      category_path AS (
        WITH RECURSIVE cp AS (
          SELECT c.cat_id, c.name, c.parent_id, c.name::text AS path
          FROM categories c WHERE c.parent_id IS NULL
          UNION ALL
          SELECT c.cat_id, c.name, c.parent_id, (cp.path || ' > ' || c.name)::text
          FROM categories c
          JOIN cp ON c.parent_id = cp.cat_id
        )
        SELECT * FROM cp
      ),
      product_first_received AS (
        SELECT
          p.pid,
          COALESCE(p.first_received::date, MIN(r.received_date)::date) AS first_received_date
        FROM products p
        LEFT JOIN receivings r ON r.pid = p.pid
        GROUP BY p.pid, p.first_received
      ),
      recent_products AS (
        SELECT p.pid
        FROM products p
        JOIN product_first_received fr ON fr.pid = p.pid
        JOIN params pr ON 1=1
        WHERE p.visible = true
          AND COALESCE(p.brand,'Unbranded') = pr.brand
          AND fr.first_received_date BETWEEN pr.start_date AND pr.end_date
          AND (pr.title_search IS NULL OR p.title ILIKE '%' || pr.title_search || '%')
      ),
      product_pick_category AS (
        (
          SELECT DISTINCT ON (pc.pid)
            pc.pid,
            c.name AS category_name,
            COALESCE(cp.path, c.name) AS path
          FROM product_categories pc
          JOIN categories c ON c.cat_id = pc.cat_id AND (c.type IS NULL OR c.type NOT IN (20,21))
          LEFT JOIN category_path cp ON cp.cat_id = c.cat_id
          WHERE pc.pid IN (SELECT pid FROM recent_products)
            AND (cp.path IS NULL OR (
              cp.path NOT ILIKE '%Black Friday%'
              AND cp.path NOT ILIKE '%Deals%'
            ))
            AND COALESCE(c.name, '') NOT IN ('Black Friday', 'Deals')
          ORDER BY pc.pid, length(COALESCE(cp.path,'')) DESC
        )
        UNION ALL
        (
          SELECT
            rp.pid,
            'Uncategorized'::text AS category_name,
            'Uncategorized'::text AS path
          FROM recent_products rp
          WHERE NOT EXISTS (
            SELECT 1
            FROM product_categories pc
            JOIN categories c ON c.cat_id = pc.cat_id AND (c.type IS NULL OR c.type NOT IN (20,21))
            LEFT JOIN category_path cp ON cp.cat_id = c.cat_id
            WHERE pc.pid = rp.pid
              AND (cp.path IS NULL OR (
                cp.path NOT ILIKE '%Black Friday%'
                AND cp.path NOT ILIKE '%Deals%'
              ))
              AND COALESCE(c.name, '') NOT IN ('Black Friday', 'Deals')
          )
        )
      ),
      product_sales AS (
        SELECT
          p.pid,
          p.title,
          p.sku,
          COALESCE(p.stock_quantity, 0) AS stock_quantity,
          COALESCE(p.price, 0) AS price,
          COALESCE(SUM(o.quantity), 0) AS total_sold
        FROM recent_products rp
        JOIN products p ON p.pid = rp.pid
        LEFT JOIN params pr ON true
        LEFT JOIN orders o ON o.pid = p.pid
            AND o.date::date BETWEEN pr.start_date AND pr.end_date
            AND (o.canceled IS DISTINCT FROM TRUE)
        GROUP BY p.pid, p.title, p.sku, p.stock_quantity, p.price
      )
      SELECT
        ppc.category_name,
        ppc.path,
        COUNT(ps.pid) AS num_products,
        SUM(ps.total_sold) AS total_sold,
        ROUND(AVG(COALESCE(ps.total_sold,0) / NULLIF(pr.days,0)), 2) AS avg_daily_sales,
        ROUND(AVG(COALESCE(ps.total_sold,0)), 2) AS avg_total_sold,
        MIN(ps.total_sold) AS min_total_sold,
        MAX(ps.total_sold) AS max_total_sold,
        JSON_AGG(
          JSON_BUILD_OBJECT(
            'pid', ps.pid,
            'title', ps.title,
            'sku', ps.sku,
            'total_sold', ps.total_sold,
            'categoryPath', ppc.path
          )
        ) AS products
      FROM product_sales ps
      JOIN product_pick_category ppc ON ppc.pid = ps.pid
      JOIN params pr ON true
      GROUP BY ppc.category_name, ppc.path
      HAVING SUM(ps.total_sold) >= 0
      ORDER BY (ppc.category_name = 'Uncategorized') ASC, avg_total_sold DESC NULLS LAST
      LIMIT 200;
    `;

    const { rows } = await pool.query(sql, [startISO, endISO, brand, titleSearch]);

    const shaped = rows.map(r => ({
      category_name: r.category_name,
      path: r.path,
      avg_daily_sales: Number(r.avg_daily_sales) || 0,
      total_sold: Number(r.total_sold) || 0,
      num_products: Number(r.num_products) || 0,
      avgTotalSold: Number(r.avg_total_sold) || 0,
      minSold: Number(r.min_total_sold) || 0,
      maxSold: Number(r.max_total_sold) || 0,
      products: Array.isArray(r.products) ? r.products : []
    }));

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

// Enhanced forecast endpoint: returns flat product list with line/artist/category/metrics
// for client-side grouping by line or category
router.get('/forecast-v2', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const brand = (req.query.brand || '').toString();
    const startDateStr = req.query.startDate;
    const endDateStr = req.query.endDate;

    if (!brand) {
      return res.status(400).json({ error: 'Missing required parameter: brand' });
    }

    const endISO = endDateStr ? businessDateOf(endDateStr) : businessTodayStr();
    const startISO = startDateStr
      ? businessDateOf(startDateStr)
      : new Date(Date.parse(endISO) - 29 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);

    const sql = `
      WITH params AS (
        SELECT $1::date AS start_date, $2::date AS end_date, $3::text AS brand
      ),
      category_path AS (
        WITH RECURSIVE cp AS (
          SELECT c.cat_id, c.name, c.parent_id, c.name::text AS path
          FROM categories c WHERE c.parent_id IS NULL
          UNION ALL
          SELECT c.cat_id, c.name, c.parent_id, (cp.path || ' > ' || c.name)::text
          FROM categories c JOIN cp ON c.parent_id = cp.cat_id
        )
        SELECT * FROM cp
      ),
      product_first_received AS (
        SELECT
          p.pid,
          COALESCE(p.first_received::date, MIN(r.received_date)::date) AS first_received_date
        FROM products p
        LEFT JOIN receivings r ON r.pid = p.pid
        GROUP BY p.pid, p.first_received
      ),
      recent_products AS (
        SELECT p.pid
        FROM products p
        JOIN product_first_received fr ON fr.pid = p.pid
        JOIN params pr ON 1=1
        WHERE p.visible = true
          AND COALESCE(p.brand,'Unbranded') = pr.brand
          AND fr.first_received_date BETWEEN pr.start_date AND pr.end_date
      ),
      product_pick_category AS (
        (
          SELECT DISTINCT ON (pc.pid)
            pc.pid,
            c.name AS category_name,
            COALESCE(cp.path, c.name) AS path
          FROM product_categories pc
          JOIN categories c ON c.cat_id = pc.cat_id AND (c.type IS NULL OR c.type NOT IN (20,21))
          LEFT JOIN category_path cp ON cp.cat_id = c.cat_id
          WHERE pc.pid IN (SELECT pid FROM recent_products)
            AND (cp.path IS NULL OR (
              cp.path NOT ILIKE '%Black Friday%'
              AND cp.path NOT ILIKE '%Deals%'
            ))
            AND COALESCE(c.name, '') NOT IN ('Black Friday', 'Deals')
          ORDER BY pc.pid, length(COALESCE(cp.path,'')) DESC
        )
        UNION ALL
        (
          SELECT rp.pid, 'Uncategorized'::text, 'Uncategorized'::text
          FROM recent_products rp
          WHERE NOT EXISTS (
            SELECT 1
            FROM product_categories pc
            JOIN categories c ON c.cat_id = pc.cat_id AND (c.type IS NULL OR c.type NOT IN (20,21))
            LEFT JOIN category_path cp ON cp.cat_id = c.cat_id
            WHERE pc.pid = rp.pid
              AND (cp.path IS NULL OR (
                cp.path NOT ILIKE '%Black Friday%'
                AND cp.path NOT ILIKE '%Deals%'
              ))
              AND COALESCE(c.name, '') NOT IN ('Black Friday', 'Deals')
          )
        )
      )
      SELECT
        p.pid, p.title, p.sku,
        COALESCE(p.line, '') AS line,
        COALESCE(p.artist, '') AS artist,
        ppc.category_name,
        ppc.path AS category_path,
        COALESCE(pm.lifetime_sales, 0) AS lifetime_sales,
        COALESCE(pm.first_30_days_sales, 0) AS first_30d_sales,
        COALESCE(pm.first_60_days_sales, 0) AS first_60d_sales,
        COALESCE(pm.first_90_days_sales, 0) AS first_90d_sales,
        COALESCE(pm.current_stock, 0) AS current_stock,
        COALESCE(pm.date_first_received, pfr.first_received_date)::date AS date_first_received,
        COALESCE(p.stock_quantity, 0) AS stock_quantity,
        COALESCE(p.price, 0) AS price
      FROM recent_products rp
      JOIN products p ON p.pid = rp.pid
      JOIN product_pick_category ppc ON ppc.pid = p.pid
      LEFT JOIN product_metrics pm ON pm.pid = p.pid
      LEFT JOIN product_first_received pfr ON pfr.pid = p.pid
      ORDER BY COALESCE(p.line, ''), ppc.category_name, pm.lifetime_sales DESC NULLS LAST
    `;

    const { rows } = await pool.query(sql, [startISO, endISO, brand]);

    // Collect distinct artists
    const artistSet = new Set();
    const products = rows.map(r => {
      if (r.artist) artistSet.add(r.artist);
      return {
        pid: String(r.pid),
        title: r.title,
        sku: r.sku,
        line: r.line || '',
        artist: r.artist || '',
        category: r.category_name,
        categoryPath: r.category_path,
        lifetimeSales: Number(r.lifetime_sales) || 0,
        first30dSales: Number(r.first_30d_sales) || 0,
        first60dSales: Number(r.first_60d_sales) || 0,
        first90dSales: Number(r.first_90d_sales) || 0,
        currentStock: Number(r.current_stock) || 0,
        dateFirstReceived: r.date_first_received || null,
        price: Number(r.price) || 0,
      };
    });

    res.json({
      products,
      artists: [...artistSet].sort(),
    });
  } catch (error) {
    console.error('Error fetching forecast-v2 data:', error);
    res.status(500).json({ error: 'Failed to fetch forecast data' });
  }
});

// ─── Inventory Intelligence Endpoints ────────────────────────────────────────

// Inventory KPI summary cards
router.get('/inventory-summary', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const { rows: [summary] } = await pool.query(`
      WITH agg AS (
        SELECT
          SUM(current_stock_cost) AS stock_investment,
          SUM(on_order_cost) AS on_order_value,
          CASE
            WHEN SUM(avg_stock_cost_30d) > 0
            THEN (SUM(cogs_30d) / SUM(avg_stock_cost_30d)) * 12
            ELSE 0
          END AS inventory_turns_annualized,
          CASE
            WHEN SUM(avg_stock_cost_30d) > 0
            THEN (SUM(profit_30d) / SUM(avg_stock_cost_30d)) * 12
            ELSE 0
          END AS gmroi,
          COUNT(*) FILTER (WHERE current_stock > 0) AS products_in_stock,
          COUNT(*) FILTER (WHERE is_old_stock = true AND current_stock > 0) AS dead_stock_products,
          SUM(CASE WHEN is_old_stock = true AND current_stock > 0 THEN current_stock_cost ELSE 0 END) AS dead_stock_value
        FROM product_metrics
        WHERE is_visible = true
      ),
      cover AS (
        SELECT
          PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY stock_cover_in_days) AS median_stock_cover_days
        FROM product_metrics
        WHERE is_visible = true
          AND current_stock > 0
          AND sales_velocity_daily > 0
          AND stock_cover_in_days IS NOT NULL
      )
      SELECT agg.*, cover.median_stock_cover_days
      FROM agg, cover
    `);

    res.json({
      stockInvestment: Number(summary.stock_investment) || 0,
      onOrderValue: Number(summary.on_order_value) || 0,
      inventoryTurns: Number(summary.inventory_turns_annualized) || 0,
      gmroi: Number(summary.gmroi) || 0,
      avgStockCoverDays: Number(summary.median_stock_cover_days) || 0,
      productsInStock: Number(summary.products_in_stock) || 0,
      deadStockProducts: Number(summary.dead_stock_products) || 0,
      deadStockValue: Number(summary.dead_stock_value) || 0,
    });
  } catch (error) {
    console.error('Error fetching inventory summary:', error);
    res.status(500).json({ error: 'Failed to fetch inventory summary' });
  }
});

// Daily sales activity & stockouts over time
router.get('/inventory-trends', async (req, res) => {
  try {
    const pool = req.app.locals.pool;
    const period = parseInt(req.query.period) || 30;
    const validPeriods = [30, 90, 365];
    const days = validPeriods.includes(period) ? period : 30;

    const { rows } = await pool.query(`
      SELECT
        snapshot_date AS date,
        COUNT(*) FILTER (WHERE stockout_flag = true) AS stockout_count,
        SUM(units_sold) AS units_sold
      FROM daily_product_snapshots
      WHERE snapshot_date >= CURRENT_DATE - make_interval(days => $1)
      GROUP BY snapshot_date
      ORDER BY snapshot_date
    `, [days]);

    res.json(rows.map(r => ({
      date: r.date,
      stockoutCount: Number(r.stockout_count) || 0,
      unitsSold: Number(r.units_sold) || 0,
    })));
  } catch (error) {
    console.error('Error fetching inventory trends:', error);
    res.status(500).json({ error: 'Failed to fetch inventory trends' });
  }
});

// ABC Portfolio analysis
router.get('/portfolio', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    // ABC class breakdown
    const { rows: abcBreakdown } = await pool.query(`
      SELECT
        COALESCE(abc_class, 'N/A') AS abc_class,
        COUNT(*) AS product_count,
        SUM(revenue_30d) AS revenue,
        SUM(current_stock_cost) AS stock_cost,
        SUM(profit_30d) AS profit,
        SUM(sales_30d) AS units_sold
      FROM product_metrics
      WHERE is_visible = true
      GROUP BY abc_class
      ORDER BY abc_class
    `);

    // Dead stock and overstock summary
    const { rows: [stockIssues] } = await pool.query(`
      SELECT
        COUNT(*) FILTER (WHERE is_old_stock = true AND current_stock > 0) AS dead_stock_count,
        SUM(CASE WHEN is_old_stock = true AND current_stock > 0 THEN current_stock_cost ELSE 0 END) AS dead_stock_cost,
        SUM(CASE WHEN is_old_stock = true AND current_stock > 0 THEN current_stock_retail ELSE 0 END) AS dead_stock_retail,
        COUNT(*) FILTER (WHERE overstocked_units > 0) AS overstock_count,
        SUM(COALESCE(overstocked_cost, 0)) AS overstock_cost,
        SUM(COALESCE(overstocked_retail, 0)) AS overstock_retail
      FROM product_metrics
      WHERE is_visible = true
    `);

    res.json({
      abcBreakdown: abcBreakdown.map(r => ({
        abcClass: r.abc_class,
        productCount: Number(r.product_count) || 0,
        revenue: Number(r.revenue) || 0,
        stockCost: Number(r.stock_cost) || 0,
        profit: Number(r.profit) || 0,
        unitsSold: Number(r.units_sold) || 0,
      })),
      stockIssues: {
        deadStockCount: Number(stockIssues.dead_stock_count) || 0,
        deadStockCost: Number(stockIssues.dead_stock_cost) || 0,
        deadStockRetail: Number(stockIssues.dead_stock_retail) || 0,
        overstockCount: Number(stockIssues.overstock_count) || 0,
        overstockCost: Number(stockIssues.overstock_cost) || 0,
        overstockRetail: Number(stockIssues.overstock_retail) || 0,
      },
    });
  } catch (error) {
    console.error('Error fetching portfolio analysis:', error);
    res.status(500).json({ error: 'Failed to fetch portfolio analysis' });
  }
});

// Capital efficiency — GMROI by brand (single combined query)
router.get('/efficiency', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const { rows } = await pool.query(`
      SELECT
        COALESCE(brand, 'Unbranded') AS brand_name,
        COUNT(*) AS product_count,
        SUM(current_stock_cost) AS stock_cost,
        SUM(profit_30d) AS profit_30d,
        SUM(revenue_30d) AS revenue_30d,
        CASE
          WHEN SUM(avg_stock_cost_30d) > 0
          THEN (SUM(profit_30d) / SUM(avg_stock_cost_30d)) * 12.17
          ELSE 0
        END AS gmroi
      FROM product_metrics
      WHERE is_visible = true
        AND brand IS NOT NULL
        AND current_stock_cost > 0
      GROUP BY brand
      HAVING SUM(current_stock_cost) > 100
      ORDER BY SUM(current_stock_cost) DESC
      LIMIT 30
    `);

    res.json({
      brands: rows.map(r => ({
        brand: r.brand_name,
        productCount: Number(r.product_count) || 0,
        stockCost: Number(r.stock_cost) || 0,
        profit30d: Number(r.profit_30d) || 0,
        revenue30d: Number(r.revenue_30d) || 0,
        gmroi: Number(r.gmroi) || 0,
      })),
    });
  } catch (error) {
    console.error('Error fetching capital efficiency:', error);
    res.status(500).json({ error: 'Failed to fetch capital efficiency' });
  }
});

// Demand & stock health
router.get('/stock-health', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    // Stock cover distribution (histogram buckets)
    const { rows: coverDistribution } = await pool.query(`
      SELECT
        CASE
          WHEN stock_cover_in_days IS NULL OR stock_cover_in_days <= 0 THEN '0 (Stockout)'
          WHEN stock_cover_in_days <= 7 THEN '1-7 days'
          WHEN stock_cover_in_days <= 14 THEN '8-14 days'
          WHEN stock_cover_in_days <= 30 THEN '15-30 days'
          WHEN stock_cover_in_days <= 60 THEN '31-60 days'
          WHEN stock_cover_in_days <= 90 THEN '61-90 days'
          WHEN stock_cover_in_days <= 180 THEN '91-180 days'
          ELSE '180+ days'
        END AS bucket,
        CASE
          WHEN stock_cover_in_days IS NULL OR stock_cover_in_days <= 0 THEN 0
          WHEN stock_cover_in_days <= 7 THEN 1
          WHEN stock_cover_in_days <= 14 THEN 2
          WHEN stock_cover_in_days <= 30 THEN 3
          WHEN stock_cover_in_days <= 60 THEN 4
          WHEN stock_cover_in_days <= 90 THEN 5
          WHEN stock_cover_in_days <= 180 THEN 6
          ELSE 7
        END AS sort_order,
        COUNT(*) AS product_count,
        SUM(current_stock_cost) AS stock_cost
      FROM product_metrics
      WHERE is_visible = true
        AND is_replenishable = true
        AND sales_30d > 0
      GROUP BY 1, 2
      ORDER BY sort_order
    `);

    // Demand pattern distribution
    const { rows: demandPatterns } = await pool.query(`
      SELECT
        COALESCE(demand_pattern, 'unknown') AS pattern,
        COUNT(*) AS product_count,
        SUM(revenue_30d) AS revenue,
        SUM(current_stock_cost) AS stock_cost
      FROM product_metrics
      WHERE is_visible = true
        AND sales_30d > 0
      GROUP BY demand_pattern
      ORDER BY COUNT(*) DESC
    `);

    // Service level / stockout summary
    const { rows: [serviceStats] } = await pool.query(`
      SELECT
        ROUND(AVG(fill_rate_30d)::numeric, 1) AS avg_fill_rate,
        ROUND(AVG(service_level_30d)::numeric, 1) AS avg_service_level,
        SUM(stockout_incidents_30d) AS total_stockout_incidents,
        SUM(lost_sales_incidents_30d) AS total_lost_sales_incidents,
        SUM(forecast_lost_sales_units) AS total_lost_units,
        SUM(forecast_lost_revenue) AS total_lost_revenue,
        COUNT(*) FILTER (WHERE stockout_days_30d > 0) AS products_with_stockouts,
        ROUND(AVG(stockout_rate_30d)::numeric, 1) AS avg_stockout_rate
      FROM product_metrics
      WHERE is_visible = true
        AND is_replenishable = true
        AND sales_30d > 0
    `);

    res.json({
      coverDistribution: coverDistribution.map(r => ({
        bucket: r.bucket,
        productCount: Number(r.product_count) || 0,
        stockCost: Number(r.stock_cost) || 0,
      })),
      demandPatterns: demandPatterns.map(r => ({
        pattern: r.pattern,
        productCount: Number(r.product_count) || 0,
        revenue: Number(r.revenue) || 0,
        stockCost: Number(r.stock_cost) || 0,
      })),
      serviceStats: {
        avgFillRate: Number(serviceStats.avg_fill_rate) || 0,
        avgServiceLevel: Number(serviceStats.avg_service_level) || 0,
        totalStockoutIncidents: Number(serviceStats.total_stockout_incidents) || 0,
        totalLostSalesIncidents: Number(serviceStats.total_lost_sales_incidents) || 0,
        totalLostUnits: Number(serviceStats.total_lost_units) || 0,
        totalLostRevenue: Number(serviceStats.total_lost_revenue) || 0,
        productsWithStockouts: Number(serviceStats.products_with_stockouts) || 0,
        avgStockoutRate: Number(serviceStats.avg_stockout_rate) || 0,
      },
    });
  } catch (error) {
    console.error('Error fetching stock health:', error);
    res.status(500).json({ error: 'Failed to fetch stock health' });
  }
});

// Aging & sell-through by age cohort
router.get('/aging', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const { rows } = await pool.query(`
      SELECT
        CASE
          WHEN age_days <= 30 THEN '0-30d'
          WHEN age_days <= 60 THEN '31-60d'
          WHEN age_days <= 90 THEN '61-90d'
          WHEN age_days <= 180 THEN '91-180d'
          WHEN age_days <= 365 THEN '181-365d'
          ELSE '365d+'
        END AS cohort,
        CASE
          WHEN age_days <= 30 THEN 0
          WHEN age_days <= 60 THEN 1
          WHEN age_days <= 90 THEN 2
          WHEN age_days <= 180 THEN 3
          WHEN age_days <= 365 THEN 4
          ELSE 5
        END AS sort_order,
        COUNT(*) AS product_count,
        ROUND(AVG(
          CASE WHEN avg_stock_units_30d > 0
            THEN (sales_30d::numeric / avg_stock_units_30d) * 100
          END
        )::numeric, 1) AS avg_sell_through,
        SUM(current_stock_cost) AS stock_cost,
        SUM(revenue_30d) AS revenue,
        SUM(sales_30d) AS units_sold
      FROM product_metrics
      WHERE is_visible = true
        AND current_stock > 0
        AND age_days IS NOT NULL
      GROUP BY 1, 2
      ORDER BY sort_order
    `);

    res.json(rows.map(r => ({
      cohort: r.cohort,
      productCount: Number(r.product_count) || 0,
      avgSellThrough: Number(r.avg_sell_through) || 0,
      stockCost: Number(r.stock_cost) || 0,
      revenue: Number(r.revenue) || 0,
      unitsSold: Number(r.units_sold) || 0,
    })));
  } catch (error) {
    console.error('Error fetching aging data:', error);
    res.status(500).json({ error: 'Failed to fetch aging data' });
  }
});

// Reorder risk — lead time vs sells_out_in_days
router.get('/stockout-risk', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    // CTE shared by chart data and summary
    const leadTimeSql = `
      LEAST(180, CASE
        WHEN avg_lead_time_days IS NOT NULL AND avg_lead_time_days > 0 THEN avg_lead_time_days
        WHEN config_lead_time IS NOT NULL AND config_lead_time > 0 THEN config_lead_time
        ELSE 14
      END)`;

    // Summary: accurate counts across ALL products (not just the chart sample)
    const { rows: [summary] } = await pool.query(`
      SELECT
        COUNT(*) FILTER (WHERE sells_out_in_days <= ${leadTimeSql}) AS at_risk_count,
        COUNT(*) FILTER (WHERE sells_out_in_days <= ${leadTimeSql} AND abc_class = 'A') AS critical_a_count,
        COALESCE(SUM(revenue_30d) FILTER (WHERE sells_out_in_days <= ${leadTimeSql}), 0) AS at_risk_revenue
      FROM product_metrics
      WHERE is_visible = true
        AND is_replenishable = true
        AND sells_out_in_days IS NOT NULL
        AND sells_out_in_days > 0
        AND sales_30d > 0
    `);

    // Sample products on both sides of the risk line so the diagonal is meaningful.
    // 60 at-risk (buffer <= 0), 40 closest safe (buffer > 0).
    const { rows } = await pool.query(`
      WITH base AS (
        SELECT
          title, sku, brand,
          ${leadTimeSql} AS lead_time_days,
          sells_out_in_days, current_stock, sales_velocity_daily,
          revenue_30d, abc_class
        FROM product_metrics
        WHERE is_visible = true
          AND is_replenishable = true
          AND sells_out_in_days IS NOT NULL
          AND sells_out_in_days > 0
          AND sales_30d > 0
      )
      (SELECT * FROM base WHERE sells_out_in_days <= lead_time_days
       ORDER BY (sells_out_in_days - lead_time_days) ASC LIMIT 60)
      UNION ALL
      (SELECT * FROM base WHERE sells_out_in_days > lead_time_days
       ORDER BY (sells_out_in_days - lead_time_days) ASC LIMIT 40)
    `);

    res.json({
      summary: {
        atRiskCount: Number(summary.at_risk_count) || 0,
        criticalACount: Number(summary.critical_a_count) || 0,
        atRiskRevenue: Number(summary.at_risk_revenue) || 0,
      },
      products: rows.map(r => ({
        title: r.title,
        sku: r.sku,
        brand: r.brand,
        leadTimeDays: Number(r.lead_time_days) || 0,
        sellsOutInDays: Number(r.sells_out_in_days) || 0,
        currentStock: Number(r.current_stock) || 0,
        velocityDaily: Number(r.sales_velocity_daily) || 0,
        revenue30d: Number(r.revenue_30d) || 0,
        abcClass: r.abc_class || 'N/A',
      })),
    });
  } catch (error) {
    console.error('Error fetching stockout risk:', error);
    res.status(500).json({ error: 'Failed to fetch stockout risk' });
  }
});

// Discount / markdown impact
router.get('/discounts', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const { rows } = await pool.query(`
      SELECT
        COALESCE(abc_class, 'N/A') AS abc_class,
        CASE
          WHEN discount_rate_30d IS NULL OR discount_rate_30d <= 0 THEN 'No Discount'
          WHEN discount_rate_30d <= 10 THEN '1-10%'
          WHEN discount_rate_30d <= 20 THEN '11-20%'
          WHEN discount_rate_30d <= 30 THEN '21-30%'
          ELSE '30%+'
        END AS discount_bucket,
        CASE
          WHEN discount_rate_30d IS NULL OR discount_rate_30d <= 0 THEN 0
          WHEN discount_rate_30d <= 10 THEN 1
          WHEN discount_rate_30d <= 20 THEN 2
          WHEN discount_rate_30d <= 30 THEN 3
          ELSE 4
        END AS sort_order,
        COUNT(*) AS product_count,
        ROUND(AVG(CASE WHEN avg_stock_units_30d > 0 THEN (sales_30d::numeric / avg_stock_units_30d) * 100 END)::numeric, 1) AS avg_sell_through,
        SUM(revenue_30d) AS revenue,
        SUM(discounts_30d) AS discount_amount,
        SUM(profit_30d) AS profit
      FROM product_metrics
      WHERE is_visible = true
        AND sales_30d > 0
        AND abc_class IS NOT NULL
      GROUP BY 1, 2, 3
      ORDER BY abc_class, sort_order
    `);

    res.json(rows.map(r => ({
      abcClass: r.abc_class,
      discountBucket: r.discount_bucket,
      productCount: Number(r.product_count) || 0,
      avgSellThrough: Number(r.avg_sell_through) || 0,
      revenue: Number(r.revenue) || 0,
      discountAmount: Number(r.discount_amount) || 0,
      profit: Number(r.profit) || 0,
    })));
  } catch (error) {
    console.error('Error fetching discount analysis:', error);
    res.status(500).json({ error: 'Failed to fetch discount analysis' });
  }
});

// YoY growth momentum
router.get('/growth', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    // ABC breakdown — only "comparable" products (sold in BOTH periods, i.e. growth != -100%)
    const { rows } = await pool.query(`
      SELECT
        COALESCE(abc_class, 'N/A') AS abc_class,
        CASE
          WHEN sales_growth_yoy > 50 THEN 'Strong Growth (>50%)'
          WHEN sales_growth_yoy > 0 THEN 'Growing (0-50%)'
          WHEN sales_growth_yoy > -50 THEN 'Declining (0-50%)'
          ELSE 'Sharp Decline (>50%)'
        END AS growth_bucket,
        CASE
          WHEN sales_growth_yoy > 50 THEN 0
          WHEN sales_growth_yoy > 0 THEN 1
          WHEN sales_growth_yoy > -50 THEN 2
          ELSE 3
        END AS sort_order,
        COUNT(*) AS product_count,
        SUM(revenue_30d) AS revenue,
        SUM(current_stock_cost) AS stock_cost
      FROM product_metrics
      WHERE is_visible = true
        AND sales_growth_yoy IS NOT NULL
        AND sales_30d > 0
      GROUP BY 1, 2, 3
      ORDER BY abc_class, sort_order
    `);

    // Summary: comparable products (sold in both periods) with revenue-weighted avg
    const { rows: [summary] } = await pool.query(`
      SELECT
        COUNT(*) AS comparable_count,
        COUNT(*) FILTER (WHERE sales_growth_yoy > 0) AS growing_count,
        COUNT(*) FILTER (WHERE sales_growth_yoy <= 0) AS declining_count,
        ROUND(
          CASE WHEN SUM(revenue_30d) > 0
            THEN SUM(sales_growth_yoy * revenue_30d) / SUM(revenue_30d)
            ELSE 0
          END::numeric, 1
        ) AS weighted_avg_growth,
        ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sales_growth_yoy)::numeric, 1) AS median_growth
      FROM product_metrics
      WHERE is_visible = true
        AND sales_growth_yoy IS NOT NULL
        AND sales_30d > 0
    `);

    // Catalog turnover: new products (selling now, no sales last year) and discontinued (sold last year, not now)
    const { rows: [turnover] } = await pool.query(`
      SELECT
        COUNT(*) FILTER (WHERE sales_growth_yoy IS NULL AND sales_30d > 0 AND age_days < 365) AS new_products,
        SUM(revenue_30d) FILTER (WHERE sales_growth_yoy IS NULL AND sales_30d > 0 AND age_days < 365) AS new_product_revenue,
        COUNT(*) FILTER (WHERE sales_growth_yoy = -100) AS discontinued,
        SUM(current_stock_cost) FILTER (WHERE sales_growth_yoy = -100 AND current_stock > 0) AS discontinued_stock_value
      FROM product_metrics
      WHERE is_visible = true
    `);

    res.json({
      byClass: rows.map(r => ({
        abcClass: r.abc_class,
        growthBucket: r.growth_bucket,
        productCount: Number(r.product_count) || 0,
        revenue: Number(r.revenue) || 0,
        stockCost: Number(r.stock_cost) || 0,
      })),
      summary: {
        comparableCount: Number(summary.comparable_count) || 0,
        growingCount: Number(summary.growing_count) || 0,
        decliningCount: Number(summary.declining_count) || 0,
        weightedAvgGrowth: Number(summary.weighted_avg_growth) || 0,
        medianGrowth: Number(summary.median_growth) || 0,
      },
      turnover: {
        newProducts: Number(turnover.new_products) || 0,
        newProductRevenue: Number(turnover.new_product_revenue) || 0,
        discontinued: Number(turnover.discontinued) || 0,
        discontinuedStockValue: Number(turnover.discontinued_stock_value) || 0,
      },
    });
  } catch (error) {
    console.error('Error fetching growth data:', error);
    res.status(500).json({ error: 'Failed to fetch growth data' });
  }
});

// Inventory value over time (uses stock_snapshots — full product coverage)
router.get('/inventory-value', async (req, res) => {
  try {
    const pool = req.app.locals.pool;
    const period = parseInt(req.query.period) || 90;
    const validPeriods = [30, 90, 365];
    const days = validPeriods.includes(period) ? period : 90;

    const { rows } = await pool.query(`
      SELECT
        snapshot_date AS date,
        ROUND(SUM(stock_value)::numeric, 0) AS total_value,
        COUNT(DISTINCT pid) AS product_count
      FROM stock_snapshots
      WHERE snapshot_date >= CURRENT_DATE - make_interval(days => $1)
      GROUP BY snapshot_date
      ORDER BY snapshot_date
    `, [days]);

    res.json(rows.map(r => ({
      date: r.date,
      totalValue: Number(r.total_value) || 0,
      productCount: Number(r.product_count) || 0,
    })));
  } catch (error) {
    console.error('Error fetching inventory value:', error);
    res.status(500).json({ error: 'Failed to fetch inventory value' });
  }
});

// Inventory flow: receiving vs selling per day
router.get('/flow', async (req, res) => {
  try {
    const pool = req.app.locals.pool;
    const period = parseInt(req.query.period) || 30;
    const validPeriods = [30, 90];
    const days = validPeriods.includes(period) ? period : 30;

    const { rows } = await pool.query(`
      SELECT
        snapshot_date AS date,
        COALESCE(SUM(units_received), 0) AS units_received,
        ROUND(COALESCE(SUM(cost_received), 0)::numeric, 0) AS cost_received,
        COALESCE(SUM(units_sold), 0) AS units_sold,
        ROUND(COALESCE(SUM(cogs), 0)::numeric, 0) AS cogs_sold
      FROM daily_product_snapshots
      WHERE snapshot_date >= CURRENT_DATE - make_interval(days => $1)
      GROUP BY snapshot_date
      ORDER BY snapshot_date
    `, [days]);

    res.json(rows.map(r => ({
      date: r.date,
      unitsReceived: Number(r.units_received) || 0,
      costReceived: Number(r.cost_received) || 0,
      unitsSold: Number(r.units_sold) || 0,
      cogsSold: Number(r.cogs_sold) || 0,
    })));
  } catch (error) {
    console.error('Error fetching inventory flow:', error);
    res.status(500).json({ error: 'Failed to fetch inventory flow' });
  }
});

// Seasonal pattern distribution
router.get('/seasonal', async (req, res) => {
  try {
    const pool = req.app.locals.pool;

    const { rows: patterns } = await pool.query(`
      SELECT
        COALESCE(seasonal_pattern, 'unknown') AS pattern,
        COUNT(*) AS product_count,
        SUM(current_stock_cost) AS stock_cost,
        SUM(revenue_30d) AS revenue
      FROM product_metrics
      WHERE is_visible = true
        AND current_stock > 0
      GROUP BY seasonal_pattern
      ORDER BY COUNT(*) DESC
    `);

    const { rows: peakSeasons } = await pool.query(`
      SELECT
        peak_season AS month,
        COUNT(*) AS product_count,
        SUM(current_stock_cost) AS stock_cost
      FROM product_metrics
      WHERE is_visible = true
        AND current_stock > 0
        AND seasonal_pattern IN ('moderate', 'strong')
        AND peak_season IS NOT NULL
      GROUP BY peak_season
      ORDER BY
        CASE peak_season
          WHEN 'January' THEN 1 WHEN 'February' THEN 2 WHEN 'March' THEN 3
          WHEN 'April' THEN 4 WHEN 'May' THEN 5 WHEN 'June' THEN 6
          WHEN 'July' THEN 7 WHEN 'August' THEN 8 WHEN 'September' THEN 9
          WHEN 'October' THEN 10 WHEN 'November' THEN 11 WHEN 'December' THEN 12
          ELSE 13
        END
    `);

    res.json({
      patterns: patterns.map(r => ({
        pattern: r.pattern,
        productCount: Number(r.product_count) || 0,
        stockCost: Number(r.stock_cost) || 0,
        revenue: Number(r.revenue) || 0,
      })),
      peakSeasons: peakSeasons.map(r => ({
        month: r.month,
        productCount: Number(r.product_count) || 0,
        stockCost: Number(r.stock_cost) || 0,
      })),
    });
  } catch (error) {
    console.error('Error fetching seasonal data:', error);
    res.status(500).json({ error: 'Failed to fetch seasonal data' });
  }
});

export default router;
