"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.billingModuleReport = void 0;
const auth_base_1 = require("@things-factory/auth-base");
const biz_base_1 = require("@things-factory/biz-base");
exports.billingModuleReport = {
    async billingModuleReport(_, params, context) {
        try {
            const { tx } = context.state;
            let bizplaceFilter = { name: '', operator: '', value: '' };
            let userFilter = params.filters.find(data => data.name === 'user');
            let fromDate = params.filters.find(data => data.name === 'fromDate');
            let toDate = params.filters.find(data => data.name === 'toDate');
            let locationType = params.filters.find(data => data.name === 'locationType');
            if (userFilter) {
                const user = await tx.getRepository(auth_base_1.User).findOne({
                    where: { id: userFilter.value },
                    relations: ['bizplaces']
                });
                const bizplace = user.bizplaces[0];
                if (!bizplace)
                    throw 'Invalid input';
                bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id };
            }
            else {
                bizplaceFilter = params.filters.find(data => data.name === 'bizplace');
            }
            if (!bizplaceFilter || !fromDate || !toDate)
                throw 'Invalid input';
            const bizplace = await tx.getRepository(biz_base_1.Bizplace).findOne({
                id: bizplaceFilter.value
            });
            // Prepare dynamic locationType clause and query params 
            const queryParams = [context.state.domain.id, bizplace.id];
            let locationTypeClause = '';
            if (locationType && locationType.value) {
                locationTypeClause = 'AND l.type = $3';
                queryParams.push(locationType.value);
            }
            console.time('temp');
            await tx.query(`
        CREATE TEMP TABLE temp_data_src ON COMMIT DROP AS (
          -- Inventory Histories
          SELECT 
            invh.inventory_id,
            UPPER(TRIM(invh.packing_type)) AS packing_type,
            CASE 
              WHEN invh.order_no ILIKE 'RTO-%' OR invh.transaction_type = 'RETURN' THEN REPLACE((transaction_type)::text, 'UNLOADING', 'RETURN')
              WHEN invh.transaction_type = 'RETURN' THEN REPLACE((transaction_type)::text, 'RETURN', 'RETURN') 
              ELSE invh.transaction_type 
            END AS transaction_type, 
            invh.status, invh.created_at + INTERVAL '8 hours' AS created_at, 
            invh.qty, 
            invh.opening_qty,
            pd.volume,
            l."type" as location, 
            w."type" as warehouse, 
            invh.domain_id, 
            invh.bizplace_id
          FROM reduced_inventory_histories invh
          INNER JOIN inventories i on i.id = invh.inventory_id
          INNER JOIN locations l on l.id = i.location_id 
          INNER JOIN warehouses w on w.id = l.warehouse_id 
          LEFT JOIN product_details pd ON pd.id = i.product_detail_id
          WHERE
            invh.domain_id = $1
            AND invh.bizplace_id = $2
            ${locationTypeClause}
        UNION ALL        

        -- VAS Records
        SELECT 
          ov.inventory_id,
          UPPER(TRIM(COALESCE(ov.new_packing_type, ov.packing_type))) AS packing_type,
          'VAS' AS transaction_type,
          'VAS' AS status,
          ov.updated_at + interval '8 hours' AS created_at,
          COALESCE(ov.adjusted_output_qty, ov.qty) AS qty,
          '0' as opening_qty,
          COALESCE(p.volume, 0) as volume,
          '-' as location,
          '-' as warehouse,
          ov.domain_id, 
          ov.bizplace_id
        FROM order_vass ov
        LEFT JOIN products p ON p.id = ov.target_product_id
        WHERE
          ov.domain_id = $1
          AND ov.bizplace_id = $2
          AND ov.qty IS NOT NULL
      );
      `, queryParams);
            console.timeEnd('temp');
            const result = await tx.query(`
       WITH RECURSIVE date_series AS (
          SELECT 
          CASE 
            WHEN $1::DATE < (SELECT MIN(created_at)::DATE FROM temp_data_src) 
            THEN (SELECT (MIN(created_at)+ INTERVAL '1 DAY')::DATE FROM temp_data_src)
          ELSE $1 ::DATE 
          END AS query_date
          UNION ALL
          SELECT (query_date + INTERVAL '1 DAY')::DATE
          FROM date_series
          WHERE query_date < $2
      ),
      distinct_groups AS (
          SELECT DISTINCT 
            UPPER(TRIM(packing_type)) AS packing_type,
            warehouse, 
            location
          FROM temp_data_src
          WHERE packing_type IS NOT NULL
      ),
      date_packing_combinations AS (
          SELECT DISTINCT ds.query_date, pt.packing_type
          FROM date_series ds
          CROSS JOIN distinct_groups pt
      ),
      order_number AS(
        SELECT 
        rg.name,
        (rg.updated_at + interval '8 hours')::DATE AS query_date
        FROM release_goods rg 
        INNER JOIN (SELECT domain_id, bizplace_id FROM temp_data_src src limit 1)src 
          ON rg.domain_id = src.domain_id 
          AND rg.bizplace_id = src.bizplace_id 
        WHERE rg.status = 'DONE'
      ),
      inbound AS (
          SELECT 
              dpc.query_date,
              SUM(COALESCE(src.opening_qty, 0)) AS qty,
              'Inbound ' || '(' || INITCAP(dpc.packing_type) || ')' AS data_type
          FROM date_packing_combinations dpc
          LEFT JOIN temp_data_src src 
              ON dpc.query_date = src.created_at::DATE
              AND src.transaction_type = 'PUTAWAY'
              AND dpc.packing_type = src.packing_type
          GROUP BY dpc.query_date, dpc.packing_type
          ORDER BY dpc.query_date
      ),
      outbound AS (
          SELECT 
              dpc.query_date,
              SUM(ABS(COALESCE(src.qty, 0))) AS qty,
              'Outbound ' || '(' || INITCAP(dpc.packing_type) || ')' AS data_type
          FROM date_packing_combinations dpc
          LEFT JOIN temp_data_src src 
              ON dpc.query_date = src.created_at::DATE
              AND src.transaction_type = 'PICKING'
              AND dpc.packing_type = src.packing_type
          GROUP BY dpc.query_date, dpc.packing_type
          ORDER BY dpc.query_date
      ),
      return AS (
          SELECT 
              dpc.query_date,
              SUM(COALESCE(src.qty, 0)) AS qty,
              'Return ' || '(' || INITCAP(dpc.packing_type) || ')' AS data_type
          FROM date_packing_combinations dpc
          LEFT JOIN temp_data_src src 
              ON dpc.query_date = src.created_at::DATE
              AND src.transaction_type = 'RETURN'
              AND dpc.packing_type = src.packing_type
          GROUP BY dpc.query_date, dpc.packing_type
          ORDER BY dpc.query_date
      ),
      vas AS(
          SELECT 
              dpc.query_date,
              SUM(COALESCE(src.qty, 0)) AS qty,
              'Vas ' || '(' || INITCAP(dpc.packing_type) || ')' AS data_type
          FROM date_packing_combinations dpc
          LEFT JOIN temp_data_src src  
              ON dpc.query_date = src.created_at::DATE
              AND src.transaction_type = 'VAS'
              AND dpc.packing_type = src.packing_type
          GROUP BY dpc.query_date, dpc.packing_type
          ORDER BY dpc.query_date
      ),
      orders AS(
        SELECT 
          dpc.query_date,
          COUNT(DISTINCT rg.name) AS qty,
          'Total Order Fulfilled' AS data_type
        FROM date_series dpc 
        LEFT JOIN order_number rg ON dpc.query_date = rg.query_date  
        GROUP BY dpc.query_date
        ORDER BY dpc.query_date  
      ),
      total_unit_processed AS(
        SELECT
          o.query_date,
          SUM(ABS(qty)) as qty,
          'Total Unit Processed' AS data_type
        FROM outbound o
        GROUP BY o.query_date
        ORDER BY o.query_date
      ),
      inbound_volume AS (
        SELECT
          dpc.query_date,
          SUM(COALESCE(src.qty * src.volume, 0)) AS qty,
          'Inbound (CBM)' AS data_type
        FROM date_packing_combinations dpc
        LEFT JOIN temp_data_src src
          ON dpc.query_date = src.created_at::DATE
          AND src.transaction_type IN ('UNLOADING', 'RETURN')
          AND dpc.packing_type = src.packing_type
        GROUP BY dpc.query_date
      ),
      outbound_volume AS (
        SELECT
          dpc.query_date,
          SUM(ABS(COALESCE(src.qty * src.volume, 0))) AS qty,
          'Outbound (CBM)' AS data_type
        FROM date_packing_combinations dpc
        LEFT JOIN temp_data_src src
          ON dpc.query_date = src.created_at::DATE
          AND src.transaction_type = 'PICKING'
          AND dpc.packing_type = src.packing_type
        GROUP BY dpc.query_date  
      ),
      vas_volume AS (
        SELECT 
          dpc.query_date,
          SUM(COALESCE(src.qty * src.volume, 0)) AS qty,
          'VAS (CBM)' AS data_type
        FROM date_packing_combinations dpc
        LEFT JOIN temp_data_src src
          ON dpc.query_date = src.created_at::DATE
          AND src.transaction_type = 'VAS'
          AND dpc.packing_type = src.packing_type
        GROUP BY dpc.query_date
      ),
      -- Determine the cutoff date from date_series.
      cutoff AS (
        SELECT MIN(query_date) AS cutoff_date 
        FROM date_series
      ),
      -- For each unique inventory_id, return the row with the latest created_at (before cutoff)
      -- and calculate its effective opening using opening_qty + qty.
      latest_opening AS (
        SELECT DISTINCT ON (inventory_id)
              inventory_id,
              packing_type,
              warehouse,
              location,
              (COALESCE(opening_qty, 0) + COALESCE(qty, 0)) AS effective_opening,
              created_at AS last_record_date
        FROM temp_data_src, cutoff
        WHERE created_at::DATE < cutoff.cutoff_date
        ORDER BY inventory_id, created_at DESC
      ),
      ---------------group by locations----------------
      -- Aggregate the effective_opening from the latest record (per inventory_id) by group.
      first_count AS (
          SELECT  
              cutoff.cutoff_date AS query_date,
              SUM(effective_opening) AS opening_balance,
              0 AS closing_qty,
              packing_type,
              warehouse,
              location
          FROM latest_opening, cutoff
          GROUP BY packing_type, warehouse, location, cutoff.cutoff_date
      ),
      day_transaction AS (
          SELECT 
              ds.query_date,
              COALESCE(SUM(src.qty), 0) AS qty,
              dg.packing_type, dg.warehouse, dg.location
          FROM date_series ds
          CROSS JOIN distinct_groups dg
          LEFT JOIN temp_data_src src
              ON src.created_at::DATE = ds.query_date
              AND src.packing_type = dg.packing_type
              AND src.warehouse = dg.warehouse
              AND src.location = dg.location
          GROUP BY ds.query_date, dg.packing_type, dg.warehouse, dg.location
      ),
      c_transaction AS (
          SELECT 
              dt.query_date,
              dt.qty, 
              SUM(dt.qty) OVER (PARTITION BY dt.packing_type, dt.warehouse, dt.location ORDER BY dt.query_date) AS c_qty,
              dt.packing_type, dt.warehouse, dt.location
          FROM day_transaction dt
      ),
      by_day_qty AS(
        SELECT * from first_count
        UNION ALL
        SELECT 
            (ct.query_date + interval '1 day')::DATE as query_date,
            fc.opening_balance + ct.c_qty AS opening_balance,
            0 AS closing_qty,
            ct.packing_type, ct.warehouse, ct.location
        FROM c_transaction ct
        JOIN first_count fc
            ON fc.packing_type = ct.packing_type 
          AND ct.warehouse = fc.warehouse 
          AND ct.location = fc.location
        WHERE ct.query_date < (SELECT MAX(query_date) FROM date_series)
        ORDER BY packing_type, warehouse, location, query_date
      ),
      by_location AS(
        SELECT 
          query_date,
          opening_balance as opening_balance,
          INITCAP(SUBSTRING(warehouse FROM 1 FOR 1)) || LOWER(SUBSTRING(warehouse FROM 2)) || ' ' || 
          INITCAP(SUBSTRING(location FROM 1 FOR 1)) || LOWER(SUBSTRING(location FROM 2)) || ' (' || 
          INITCAP(SUBSTRING(packing_type FROM 1 FOR 1)) || LOWER(SUBSTRING(packing_type FROM 2)) || ')' as data_type
        FROM by_day_qty
        ORDER BY data_type, query_date
      )
      
      SELECT * FROM inbound
      UNION ALL
      SELECT * FROM outbound
      UNION ALL
      SELECT * FROM return
      UNION ALL
      SELECT * FROM vas
      UNION ALL
      SELECT * FROM orders
      UNION ALL
      SELECT * FROM total_unit_processed
      UNION ALL
      SELECT * FROM by_location
      UNION ALL
      SELECT * FROM inbound_volume
      UNION ALL
      SELECT * FROM outbound_volume
      UNION ALL
      SELECT * FROM vas_volume
      ORDER BY query_date, data_type;
      `, [fromDate.value, toDate.value]);
            let items = result.map(itm => {
                return {
                    date: itm.query_date,
                    packingType: itm.data_type,
                    quantity: itm.qty
                };
            });
            return {
                items
            };
        }
        catch (error) {
            throw error;
        }
    }
};
//# sourceMappingURL=billing-module-report.js.map