<?php
/**
 * Bizmart — Unified inventory metrics engine.
 *
 * @package Bizmart
 * @license GPL-2.0-or-later
 */
if (!defined('ABSPATH')) exit;

/**
 * Unified inventory metrics engine.
 *
 * Stock value = Σ (stock_qty × price) for every item that manages stock.
 *
 * Rules:
 *  1. Products with stock management ON: use their actual stock quantity.
 *  2. Products with stock management OFF but stock_status = 'instock': count as qty = 1.
 *     This avoids confusing users who see a published in-stock product but no inventory value.
 *  3. Simple / External / Grouped: count the product directly.
 *  4. Variable (parent manages stock): count the parent once, skip its variations.
 *  5. Variable (variations manage stock): count each variation, skip the parent.
 *  6. Variable (nobody manages stock, but in-stock variations): count each instock variation as qty=1.
 *  7. Purchase price lookup chain: variation _purchase_price → parent _purchase_price
 *     → variation _alg_wc_cog_cost → parent _alg_wc_cog_cost → 0.
 *  8. Negative stock is included (backorders) — reflects real liability.
 *
 * Results are cached in a transient (10 min) and invalidated by cache.php hooks.
 */

if (!function_exists('bizmart_metrics_get_inventory_totals')) {

    /**
     * Resolve purchase/cost price for a product or variation.
     *
     * @param int $id        Product or variation ID
     * @param int $parent_id Parent product ID (0 for non-variations)
     * @return float
     */
    function bizmart_metrics_resolve_purchase_price(int $id, int $parent_id = 0): float {
        // v3.0 — WAC mode: try weighted average cost first
        if (function_exists('bizmart_get_valuation_method') && bizmart_get_valuation_method() === 'wac') {
            if (function_exists('bizmart_get_wac')) {
                $wac = bizmart_get_wac($id);
                if ($wac > 0) return $wac;
                if ($parent_id > 0) {
                    $wac = bizmart_get_wac($parent_id);
                    if ($wac > 0) return $wac;
                }
            }
        }

        // 1. Own _purchase_price
        $pp = get_post_meta($id, '_purchase_price', true);
        if ($pp !== '' && $pp !== null && $pp !== false) {
            $clean = bizmart_metrics_clean_price($pp);
            if ($clean !== null) return $clean;
        }

        // 2. Parent _purchase_price (variations inherit from parent)
        if ($parent_id > 0) {
            $pp = get_post_meta($parent_id, '_purchase_price', true);
            if ($pp !== '' && $pp !== null && $pp !== false) {
                $clean = bizmart_metrics_clean_price($pp);
                if ($clean !== null) return $clean;
            }
        }

        // 3. Cost of Goods compatibility (_alg_wc_cog_cost)
        $cog = get_post_meta($id, '_alg_wc_cog_cost', true);
        if ($cog !== '' && $cog !== null && $cog !== false) {
            $clean = bizmart_metrics_clean_price($cog);
            if ($clean !== null) return $clean;
        }

        // 4. Parent CoG
        if ($parent_id > 0) {
            $cog = get_post_meta($parent_id, '_alg_wc_cog_cost', true);
            if ($cog !== '' && $cog !== null && $cog !== false) {
                $clean = bizmart_metrics_clean_price($cog);
                if ($clean !== null) return $clean;
            }
        }

        return 0.0;
    }

    /**
     * Normalise a raw price string (handles commas, spaces, currency symbols).
     *
     * @return float|null  null when the value is not numeric
     */
    function bizmart_metrics_clean_price($raw): ?float {
        if (is_numeric($raw)) return (float) $raw;
        if (!is_string($raw)) return null;

        $clean = preg_replace('/[^\d\.,-]/', '', $raw);
        // "1.234,56" → European format
        if (substr_count($clean, ',') > 0 && substr_count($clean, '.') === 0) {
            $clean = str_replace(',', '.', $clean);
        } else {
            $clean = str_replace(',', '', $clean);
        }
        return is_numeric($clean) ? (float) $clean : null;
    }

    /**
     * Calculate inventory totals: stock qty, sale value, purchase value.
     *
     * @param bool $use_cache  Whether to use/set the transient cache.
     * @return array{stock_sales_value: float, stock_purchase_value: float, total_stock_qty: float, generated_at: string}
     */
    function bizmart_metrics_get_inventory_totals(bool $use_cache = true): array {
        $blog_id   = (int) get_current_blog_id();
        $cache_key = 'bizmart_inventory_totals_v9_' . $blog_id;
        $ttl       = 10 * MINUTE_IN_SECONDS;

        if ($use_cache) {
            $cached = get_transient($cache_key);
            if (is_array($cached)
                && isset($cached['stock_sales_value'], $cached['stock_purchase_value'], $cached['total_stock_qty'])
            ) {
                return $cached;
            }
        }

        // WooCommerce not active → return zeros gracefully
        if (!function_exists('wc_get_products') || !function_exists('wc_get_product')) {
            return [
                'stock_sales_value'    => 0.0,
                'stock_purchase_value' => 0.0,
                'total_stock_qty'      => 0.0,
                'generated_at'         => current_time('mysql'),
            ];
        }

        $stock_sales_value    = 0.0;
        $stock_purchase_value = 0.0;
        $total_stock_qty      = 0.0;

        // ── Step 1: Simple / External / Grouped products ──────────────────
        $simple_products = wc_get_products([
            'limit'   => -1,
            'status'  => ['publish', 'private'],
            'type'    => ['simple', 'external', 'grouped'],
            'return'  => 'objects',
        ]);

        foreach ($simple_products as $product) {
            if ($product->managing_stock()) {
                // Stock management ON → use actual quantity
                $qty = (float) $product->get_stock_quantity();
            } elseif ($product->get_stock_status() === 'instock') {
                // Stock management OFF but product is in-stock → count as 1
                $qty = 1.0;
            } else {
                continue; // out-of-stock / on-backorder without managed stock → skip
            }
            if ($qty == 0) continue;

            $sell = (float) $product->get_price();
            $pp   = bizmart_metrics_resolve_purchase_price($product->get_id());

            $total_stock_qty      += $qty;
            $stock_sales_value    += $qty * $sell;
            $stock_purchase_value += $qty * $pp;
        }

        // ── Step 2: Variable products ───────────────────────────────────────
        $variable_products = wc_get_products([
            'limit'   => -1,
            'status'  => ['publish', 'private'],
            'type'    => ['variable'],
            'return'  => 'objects',
        ]);

        foreach ($variable_products as $parent) {
            $parent_id = $parent->get_id();

            if ($parent->managing_stock()) {
                // Parent manages stock → count parent-level stock once
                $qty = (float) $parent->get_stock_quantity();
                if ($qty == 0) continue;

                $sell = (float) $parent->get_price();
                $pp   = bizmart_metrics_resolve_purchase_price($parent_id);

                $total_stock_qty      += $qty;
                $stock_sales_value    += $qty * $sell;
                $stock_purchase_value += $qty * $pp;
            } else {
                // Check variations individually
                $children = $parent->get_children();
                foreach ($children as $var_id) {
                    $variation = wc_get_product($var_id);
                    if (!$variation || !$variation->exists()) continue;

                    $var_manage = get_post_meta($var_id, '_manage_stock', true);
                    if ($var_manage === 'yes' || $var_manage === '1') {
                        // Variation manages its own stock → use actual qty
                        $qty = (float) $variation->get_stock_quantity();
                    } elseif ($variation->get_stock_status() === 'instock') {
                        // Stock management OFF but in-stock → count as 1
                        $qty = 1.0;
                    } else {
                        continue;
                    }
                    if ($qty == 0) continue;

                    $sell = (float) $variation->get_price();
                    $pp   = bizmart_metrics_resolve_purchase_price($var_id, $parent_id);

                    $total_stock_qty      += $qty;
                    $stock_sales_value    += $qty * $sell;
                    $stock_purchase_value += $qty * $pp;
                }
            }
        }

        $totals = [
            'stock_sales_value'    => round($stock_sales_value, 2),
            'stock_purchase_value' => round($stock_purchase_value, 2),
            'total_stock_qty'      => round($total_stock_qty, 0),
            'generated_at'         => current_time('mysql'),
        ];

        set_transient($cache_key, $totals, $ttl);
        return $totals;
    }

    /**
     * Debug helper: return the detailed per-product rows used in the totals.
     *
     * @return array List of product rows with id, name, type, qty, sell, purchase
     */
    function bizmart_metrics_get_inventory_rows(): array {
        if (!function_exists('wc_get_products') || !function_exists('wc_get_product')) {
            return [];
        }

        $rows = [];

        // Simple / External / Grouped
        $simple_products = wc_get_products([
            'limit'   => -1,
            'status'  => ['publish', 'private'],
            'type'    => ['simple', 'external', 'grouped'],
            'return'  => 'objects',
        ]);

        foreach ($simple_products as $product) {
            if ($product->managing_stock()) {
                $qty = (float) $product->get_stock_quantity();
            } elseif ($product->get_stock_status() === 'instock') {
                $qty = 1.0;
            } else {
                continue;
            }
            if ($qty == 0) continue;
            $rows[] = [
                'id'     => $product->get_id(),
                'name'   => $product->get_name(),
                'type'   => $product->get_type(),
                'sku'    => $product->get_sku(),
                'qty'    => $qty,
                'sell'   => (float) $product->get_price(),
                'pp'     => bizmart_metrics_resolve_purchase_price($product->get_id()),
                'managed'=> $product->managing_stock(),
            ];
        }

        // Variable → check parent or variations
        $variable_products = wc_get_products([
            'limit'   => -1,
            'status'  => ['publish', 'private'],
            'type'    => ['variable'],
            'return'  => 'objects',
        ]);

        foreach ($variable_products as $parent) {
            $parent_id = $parent->get_id();

            if ($parent->managing_stock()) {
                $qty = (float) $parent->get_stock_quantity();
                if ($qty == 0) continue;
                $rows[] = [
                    'id'     => $parent_id,
                    'name'   => $parent->get_name() . ' (parent-managed)',
                    'type'   => 'variable',
                    'sku'    => $parent->get_sku(),
                    'qty'    => $qty,
                    'sell'   => (float) $parent->get_price(),
                    'pp'     => bizmart_metrics_resolve_purchase_price($parent_id),
                    'managed'=> true,
                ];
            } else {
                foreach ($parent->get_children() as $var_id) {
                    $variation = wc_get_product($var_id);
                    if (!$variation || !$variation->exists()) continue;
                    $var_manage = get_post_meta($var_id, '_manage_stock', true);
                    if ($var_manage === 'yes' || $var_manage === '1') {
                        $qty = (float) $variation->get_stock_quantity();
                    } elseif ($variation->get_stock_status() === 'instock') {
                        $qty = 1.0;
                    } else {
                        continue;
                    }
                    if ($qty == 0) continue;
                    $rows[] = [
                        'id'     => $var_id,
                        'name'   => $variation->get_name(),
                        'type'   => 'variation',
                        'sku'    => $variation->get_sku(),
                        'qty'    => $qty,
                        'sell'   => (float) $variation->get_price(),
                        'pp'     => bizmart_metrics_resolve_purchase_price($var_id, $parent_id),
                        'managed'=> ($var_manage === 'yes' || $var_manage === '1'),
                    ];
                }
            }
        }

        return $rows;
    }
}
