<?php
/**
 * Para Birimi İşlemleri - Integer Arithmetic
 * 
 * Tüm finansal değerler kuruş (integer) olarak işlenir
 * Float kullanımı YASAK
 * 
 * @package Odjoo
 * @category Finance
 * @author Production Team
 * @version 2.0.0
 */
class MoneyHelper
{
    /**
     * BIGINT maximum value (kuruş cinsinden)
     * ~92 trilyon TL
     */
    const MAX_SAFE_VALUE = 9223372036854775807;
    
    /**
     * TL'den kuruşa çevir
     * 
     * Desteklenen formatlar:
     * - "123.45" (noktalı ondalık)
     * - "123,45" (virgüllü ondalık)
     * - "1.234,56" (Türkçe format)
     * - "1,234.56" (İngilizce format)
     * - 123.45 (float)
     * 
     * @param string|float|int $tl TL cinsinden
     * @return int Kuruş cinsinden
     * 
     * @example
     * MoneyHelper::toKurus("123.45") // 12345
     * MoneyHelper::toKurus("1.234,56") // 123456
     */
    public static function toKurus($tl): int
    {
        if (empty($tl) || $tl === null) {
            return 0;
        }
        
        if (is_int($tl)) {
            // Zaten integer ise direkt kuruş olarak kabul et
            return $tl;
        }
        
        if (is_string($tl)) {
            // String temizleme
            $tl = trim($tl);
            
            // Boş string kontrolü
            if ($tl === '' || $tl === '0' || $tl === '0,00' || $tl === '0.00') {
                return 0;
            }
            
            // Türkçe format: "1.234,56" → "1234.56"
            // İngilizce format: "1,234.56" → "1234.56"
            
            // Son karakterin virgül mü nokta mı olduğunu kontrol et
            $lastComma = strrpos($tl, ',');
            $lastDot = strrpos($tl, '.');
            
            if ($lastComma !== false && $lastDot !== false) {
                // Her ikisi de var
                if ($lastComma > $lastDot) {
                    // Türkçe format: "1.234,56"
                    $cleaned = str_replace(['.', ','], ['', '.'], $tl);
                } else {
                    // İngilizce format: "1,234.56"
                    $cleaned = str_replace(',', '', $tl);
                }
            } elseif ($lastComma !== false) {
                // Sadece virgül var: "1234,56"
                $cleaned = str_replace(',', '.', $tl);
            } else {
                // Sadece nokta var veya hiçbiri yok: "1234.56" veya "1234"
                $cleaned = $tl;
            }
            
            $tl = (float) $cleaned;
        }
        
        // Float'tan kuruşa çevir
        $kurus = (int) round($tl * 100);
        
        // Overflow kontrolü
        if (!self::isSafe($kurus)) {
            throw new OverflowException("Para değeri çok büyük: {$kurus} kuruş");
        }
        
        return $kurus;
    }
    
    /**
     * Kuruştan TL'ye çevir
     * 
     * SADECE GÖSTERIM İÇİN kullanılmalı
     * Hesaplamalarda ASLA float kullanma
     * 
     * @param int $kurus Kuruş cinsinden
     * @return float TL cinsinden
     * 
     * @example
     * MoneyHelper::toTL(12345) // 123.45
     */
    public static function toTL(int $kurus): float
    {
        return $kurus / 100.0;
    }
    
    /**
     * Para formatla (kullanıcıya gösterim için)
     * 
     * @param int $kurus Kuruş cinsinden
     * @param string $currency Para birimi kodu
     * @param bool $showCurrency Para birimi gösterilsin mi?
     * @return string Formatlanmış tutar
     * 
     * @example
     * MoneyHelper::format(12345, 'TRY') // "123,45 TRY"
     * MoneyHelper::format(12345, 'TRY', false) // "123,45"
     */
    public static function format(int $kurus, string $currency = 'TRY', bool $showCurrency = true): string
    {
        $tl = self::toTL($kurus);
        $formatted = number_format($tl, 2, ',', '.');
        
        if ($showCurrency) {
            return $formatted . ' ' . $currency;
        }
        
        return $formatted;
    }
    
    /**
     * Form inputunu parse et
     * 
     * @param mixed $input Kullanıcı girişi
     * @return int Kuruş cinsinden
     * 
     * @example
     * MoneyHelper::parseInput($_POST['fiyat'])
     */
    public static function parseInput($input): int
    {
        if (empty($input)) {
            return 0;
        }
        
        return self::toKurus($input);
    }
    
    /**
     * Overflow kontrolü
     * 
     * @param int $kurus Kontrol edilecek değer
     * @return bool Güvenli mi?
     * 
     * @example
     * MoneyHelper::isSafe(12345) // true
     */
    public static function isSafe(int $kurus): bool
    {
        return abs($kurus) < self::MAX_SAFE_VALUE;
    }
    
    /**
     * İki kuruş değerini topla (overflow kontrolü ile)
     * 
     * @param int $kurus1 İlk değer
     * @param int $kurus2 İkinci değer
     * @return int Toplam
     * @throws OverflowException
     */
    public static function add(int $kurus1, int $kurus2): int
    {
        $result = $kurus1 + $kurus2;
        
        if (!self::isSafe($result)) {
            throw new OverflowException("Toplama işlemi overflow oluşturdu");
        }
        
        return $result;
    }
    
    /**
     * İki kuruş değerini çıkar (overflow kontrolü ile)
     * 
     * @param int $kurus1 İlk değer
     * @param int $kurus2 İkinci değer
     * @return int Fark
     * @throws OverflowException
     */
    public static function subtract(int $kurus1, int $kurus2): int
    {
        $result = $kurus1 - $kurus2;
        
        if (!self::isSafe($result)) {
            throw new OverflowException("Çıkarma işlemi overflow oluşturdu");
        }
        
        return $result;
    }
    
    /**
     * Kuruş değerini çarp (overflow kontrolü ile)
     * 
     * @param int $kurus Kuruş değeri
     * @param int $multiplier Çarpan
     * @return int Sonuç
     * @throws OverflowException
     */
    public static function multiply(int $kurus, int $multiplier): int
    {
        $result = $kurus * $multiplier;
        
        if (!self::isSafe($result)) {
            throw new OverflowException("Çarpma işlemi overflow oluşturdu");
        }
        
        return $result;
    }
    
    /**
     * Negatif mi kontrol et
     * 
     * @param int $kurus Kuruş değeri
     * @return bool
     */
    public static function isNegative(int $kurus): bool
    {
        return $kurus < 0;
    }
    
    /**
     * Pozitif mi kontrol et
     * 
     * @param int $kurus Kuruş değeri
     * @return bool
     */
    public static function isPositive(int $kurus): bool
    {
        return $kurus > 0;
    }
    
    /**
     * Sıfır mı kontrol et
     * 
     * @param int $kurus Kuruş değeri
     * @return bool
     */
    public static function isZero(int $kurus): bool
    {
        return $kurus === 0;
    }
}
