<?php
/**
 * İndirim Dağıtım Motoru - Production Grade
 * 
 * Global indirimi satırlara oransal olarak dağıtır
 * Telafi algoritması ile tam tutarı garanti eder
 * 
 * @package Odjoo
 * @category Finance
 * @author Production Team
 * @version 2.0.0
 */
class DiscountEngine
{
    /**
     * Global indirimi satırlara dağıt
     * 
     * ORANSAL DAĞITIM:
     * Her satırın net tutarına göre indirimden pay alır
     * 
     * Formül: lineDiscount = (lineNet / totalNet) * globalDiscount
     * 
     * Telafi: Fark varsa EN BÜYÜK satıra eklenir
     * 
     * @param array $lines Satır kalemleri
     * @param int $globalDiscountKurus Global indirim (kuruş)
     * @param int $totalNetKurus Toplam net tutar (kuruş)
     * @return array Güncellenmiş satırlar
     * 
     * @example
     * // Satır 1: 200 TL, Satır 2: 100 TL, Global İndirim: 50 TL
     * // Satır 1: 33.33 TL indirim
     * // Satır 2: 16.67 TL indirim
     * // Telafi: 1 kuruş fark varsa en büyük satıra eklenir
     */
    public static function distributeGlobalDiscount(
        array $lines, 
        int $globalDiscountKurus, 
        int $totalNetKurus
    ): array {
        if ($globalDiscountKurus <= 0 || $totalNetKurus <= 0) {
            return $lines;
        }
        
        if ($globalDiscountKurus > $totalNetKurus) {
            throw new InvalidArgumentException(
                "Global indirim ({$globalDiscountKurus}) toplam tutardan ({$totalNetKurus}) fazla olamaz"
            );
        }
        
        $distributedTotal = 0;
        
        // Her satıra oransal dağıt
        foreach ($lines as &$line) {
            $lineNet = $line['line_net_after_line_discount'];
            
            if ($lineNet <= 0) {
                $line['distributed_discount'] = 0;
                $line['line_net_final'] = 0;
                continue;
            }
            
            // Oransal hesaplama (integer division)
            // distributed = (lineNet / totalNet) * globalDiscount
            // = (lineNet * globalDiscount) / totalNet
            $distributedDiscount = intdiv(
                $lineNet * $globalDiscountKurus, 
                $totalNetKurus
            );
            
            $line['distributed_discount'] = $distributedDiscount;
            $line['line_net_final'] = $lineNet - $distributedDiscount;
            
            $distributedTotal += $distributedDiscount;
        }
        unset($line);
        
        // Telafi algoritması (fark varsa)
        $difference = $globalDiscountKurus - $distributedTotal;
        
        if ($difference != 0) {
            // EN BÜYÜK satıra telafi uygula (ERP best practice)
            $largestIndex = 0;
            $largestNet = 0;
            
            foreach ($lines as $index => $line) {
                if ($line['line_net_after_line_discount'] > $largestNet) {
                    $largestNet = $line['line_net_after_line_discount'];
                    $largestIndex = $index;
                }
            }
            
            $lines[$largestIndex]['distributed_discount'] += $difference;
            $lines[$largestIndex]['line_net_final'] -= $difference;
            
            // Negatif kontrolü
            if ($lines[$largestIndex]['line_net_final'] < 0) {
                throw new RuntimeException(
                    "İndirim dağıtımı sonrası negatif tutar oluştu: satır {$largestIndex}"
                );
            }
        }
        
        return $lines;
    }
    
    /**
     * Satır indirimini validate et
     * 
     * @param int $lineDiscount Satır indirimi (kuruş)
     * @param int $lineTotal Satır toplamı (kuruş)
     * @return bool Geçerli mi?
     */
    public static function validateLineDiscount(int $lineDiscount, int $lineTotal): bool
    {
        return $lineDiscount >= 0 && $lineDiscount <= $lineTotal;
    }
    
    /**
     * Global indirimi validate et
     * 
     * @param int $globalDiscount Global indirim (kuruş)
     * @param int $totalNet Toplam net (kuruş)
     * @return bool Geçerli mi?
     */
    public static function validateGlobalDiscount(int $globalDiscount, int $totalNet): bool
    {
        return $globalDiscount >= 0 && $globalDiscount <= $totalNet;
    }
}
