<?php
/**
 * TOPSIS method for product restocking prioritization
 * 
 * This function implements the Technique for Order Preference by Similarity to Ideal Solution
 * to determine which products should be prioritized for restocking based on multiple criteria.
 * Modified to match the formulas provided in the documentation.
 */
function restockWithTOPSIS($conn, $criteria_weights = null) {
    // Default weights if none provided
    if ($criteria_weights === null) {
        $criteria_weights = [
            'stock_level' => 0.4,    // Lower stock is more urgent (40% importance)
            'price_value' => 0.3,    // Higher price might indicate higher priority (30% importance)
            'turnover_rate' => 0.3   // Higher turnover rate means faster selling (30% importance)
        ];
    }
    
    // 1. Get product data from database
    $query = "SELECT b.id_barang, b.nama_barang, b.stok, b.harga, 
              COALESCE(COUNT(t.id_transaksi), 0) as sales_count 
              FROM barang b 
              LEFT JOIN detail_transaksi dt ON b.id_barang = dt.id_barangK 
              LEFT JOIN transaksi t ON dt.id_transaksi = t.id_transaksi 
              AND t.tanggal BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW() 
              GROUP BY b.id_barang";
    
    $result = mysqli_query($conn, $query);
    if (!$result) {
        return ["error" => "Database query failed: " . mysqli_error($conn)];
    }
    
    $products = [];
    while ($row = mysqli_fetch_assoc($result)) {
        // Convert price from varchar to numeric
        $row['harga'] = (float)str_replace(['Rp', '.', ','], ['', '', '.'], $row['harga']);
        
        // Calculate turnover rate (sales per stock unit)
        $row['turnover_rate'] = $row['stok'] > 0 ? $row['sales_count'] / $row['stok'] : 0;
        
        $products[] = $row;
    }
    
    if (empty($products)) {
        return ["message" => "No products found"];
    }
    
    // 2. Create decision matrix (X)
    $decision_matrix = [];
    foreach ($products as $product) {
        $decision_matrix[] = [
            'id_barang' => $product['id_barang'],
            'nama_barang' => $product['nama_barang'],
            'stock_level' => max(1, $product['stok']),  // Ensure no zero values
            'price_value' => $product['harga'],
            'turnover_rate' => $product['turnover_rate'],
        ];
    }
    
    // 3. Normalize the decision matrix (R) according to formula 3.1
    $normalized_matrix = normalizeMatrixEuclidean($decision_matrix);
    
    // 4. Apply weights to normalized matrix (Y) according to formula 3.2
    $weighted_matrix = applyWeightsToMatrix($normalized_matrix, $criteria_weights);
    
    // 5. Determine ideal and negative-ideal solutions (A+, A-) according to formula 3.3
    // Define benefit criteria (higher is better) and cost criteria (lower is better)
    $benefit_criteria = ['price_value', 'turnover_rate'];
    $cost_criteria = ['stock_level'];
    
    $ideal_solution = [];
    $negative_ideal_solution = [];
    
    // For benefit criteria: higher values are better
    // For cost criteria: lower values are better
    foreach ($benefit_criteria as $criterion) {
        $ideal_solution[$criterion] = max(array_column($weighted_matrix, $criterion));
        $negative_ideal_solution[$criterion] = min(array_column($weighted_matrix, $criterion));
    }
    
    foreach ($cost_criteria as $criterion) {
        $ideal_solution[$criterion] = min(array_column($weighted_matrix, $criterion));
        $negative_ideal_solution[$criterion] = max(array_column($weighted_matrix, $criterion));
    }
    
    // 6. Calculate separation measures (D+, D-) according to formula 3.4
    $separation_positive = [];
    $separation_negative = [];
    
    foreach ($weighted_matrix as $i => $product) {
        // Distance to positive ideal solution (D+)
        $sum_positive = 0;
        foreach (array_merge($benefit_criteria, $cost_criteria) as $criterion) {
            $sum_positive += pow($product[$criterion] - $ideal_solution[$criterion], 2);
        }
        $separation_positive[$i] = sqrt($sum_positive);
        
        // Distance to negative ideal solution (D-)
        $sum_negative = 0;
        foreach (array_merge($benefit_criteria, $cost_criteria) as $criterion) {
            $sum_negative += pow($product[$criterion] - $negative_ideal_solution[$criterion], 2);
        }
        $separation_negative[$i] = sqrt($sum_negative);
    }
    
    // 7. Calculate relative closeness to ideal solution (V) according to formula 3.5
    $preference_scores = [];
    foreach ($weighted_matrix as $i => $product) {
        // Avoid division by zero
        $denominator = $separation_negative[$i] + $separation_positive[$i];
        $preference_scores[$i] = ($denominator > 0) ? 
                               ($separation_negative[$i] / $denominator) : 0;
    }
    
    // 8. Rank products based on preference scores
    $topsis_results = [];
    foreach ($preference_scores as $i => $score) {
        $topsis_results[] = [
            'id_barang' => $decision_matrix[$i]['id_barang'],
            'nama_barang' => $decision_matrix[$i]['nama_barang'],
            'stok' => $products[$i]['stok'],
            'harga' => $products[$i]['harga'],
            'topsis_score' => $score,
            'rank' => 0  // Will be filled later
        ];
    }
    
    // Sort by preference score (descending)
    usort($topsis_results, function($a, $b) {
        return $b['topsis_score'] <=> $a['topsis_score'];
    });
    
    // Assign ranks
    foreach ($topsis_results as $i => $product) {
        $topsis_results[$i]['rank'] = $i + 1;
    }
    
    return $topsis_results;
}

/**
 * Normalize the decision matrix using Euclidean length of vector (Formula 3.1)
 * Rij = xij / sqrt(sum(xij^2))
 */
function normalizeMatrixEuclidean($matrix) {
    $normalized = [];
    $criteria = ['stock_level', 'price_value', 'turnover_rate'];
    
    // Calculate the square root of the sum of squares for each criterion
    $denominators = [];
    foreach ($criteria as $criterion) {
        $sum_squares = 0;
        foreach ($matrix as $product) {
            $sum_squares += pow($product[$criterion], 2);
        }
        $denominators[$criterion] = sqrt($sum_squares);
    }
    
    // Normalize each value according to formula 3.1
    foreach ($matrix as $i => $product) {
        $normalized[$i] = [
            'id_barang' => $product['id_barang'],
            'nama_barang' => $product['nama_barang']
        ];
        
        foreach ($criteria as $criterion) {
            // Avoid division by zero
            $normalized[$i][$criterion] = ($denominators[$criterion] > 0) ? 
                ($product[$criterion] / $denominators[$criterion]) : 0;
        }
    }
    
    return $normalized;
}

/**
 * Apply weights to the normalized matrix (Formula 3.2)
 * yij = wi * rij
 */
function applyWeightsToMatrix($matrix, $weights) {
    $weighted = [];
    $criteria = ['stock_level', 'price_value', 'turnover_rate'];
    
    foreach ($matrix as $i => $product) {
        $weighted[$i] = [
            'id_barang' => $product['id_barang'],
            'nama_barang' => $product['nama_barang']
        ];
        
        foreach ($criteria as $criterion) {
            $weighted[$i][$criterion] = $product[$criterion] * $weights[$criterion];
        }
    }
    
    return $weighted;
}
?>