from typing import Dict, List, Any
from datetime import datetime
from core.config import format_number, logger

class ZakatCalculator:
    """
    Gelişmiş Zekât Hesaplama Modülü (v2.1).
    Has (Saf) Ağırlık ve Milyem mantığına göre çalışır.
    Döviz kurlarını API üzerinden canlı çevirir.
    """
    
    # Standart Milyem Değerleri
    MILYEM_MAP = {
        "24": 0.995, "has": 0.995, "999": 0.999, "995": 0.995,
        "22": 0.916, "916": 0.916,
        "21": 0.875,
        "18": 0.750, "750": 0.750,
        "14": 0.585, "585": 0.585,
        "8": 0.333,
        "gumus": 1.00, "925": 0.925, "1000": 1.00
    }
    
    NISAP_GOLD_GRAMS = 85.00 # Diyanet standardı

    def __init__(self, main_app):
        self.main_app = main_app
        self.cm = main_app.currency_manager
        
        # Managerlara erişim
        self.stock_mgr = main_app.stock_manager       # Ürün (Product)
        self.ziynet_mgr = main_app.ziynet_stock_manager # Ziynet
        self.scrap_mgr = main_app.scrap_stock_manager   # Hurda
        
        self.prod_def_mgr = main_app.product_manager
        self.ziynet_def_mgr = main_app.ziynet_manager
        self.scrap_def_mgr = main_app.scrap_manager

    def _get_base_prices(self, rates: Dict) -> Dict[str, float]:
        """
        API'den gelen verilerden 'Has Altın' ve 'Has Gümüş' fiyatlarını (TRY) çeker.
        """
        prices = {"gold": 0.0, "silver": 0.0}
        
        # 1. Has Altın Fiyatı (Truncgil: gram-altin)
        try:
            gold_buy, gold_sell = self.cm._extract_buy_sell(rates.get("gram-altin", {}))
            prices["gold"] = gold_buy or gold_sell
        except Exception:
            prices["gold"] = 0.0
            
        # 2. Has Gümüş Fiyatı
        try:
            silver_buy, silver_sell = self.cm._extract_buy_sell(rates.get("gumus", {}))
            prices["silver"] = silver_buy or silver_sell
        except Exception:
            prices["silver"] = 0.0
            
        return prices

    def _get_purity_factor(self, karat_str: str, category: str = "") -> float:
        """
        Metin olarak gelen ayarı (örn: '22 Ayar') sayısal milyem değerine (0.916) çevirir.
        """
        k = str(karat_str).lower().strip().replace("ayar", "").replace("k", "").strip()
        cat = category.lower()
        
        if "gümüş" in cat or "gumus" in cat:
            if k in ["925", "900", "800"]: return float(k) / 1000.0
            return 1.00 # Varsayılan Has Gümüş
            
        if k in self.MILYEM_MAP:
            return self.MILYEM_MAP[k]
            
        try:
            val = float(k)
            if val > 1: return val / 1000.0
            return val
        except:
            return 0.916 # Varsayılan 22 ayar

    def calculate_report(self, nisap_start_date_str: str = None) -> Dict:
        """
        Ana Hesaplama Fonksiyonu.
        """
        # 1. Kurları Güncelle
        self.cm._fetch_all_rates()
        rates = self.cm.rates_cache
        base_prices_try = self._get_base_prices(rates)
        
        target_curr = self.main_app.display_currency
        
        # Has Fiyatları (Hedef Para Birimine Çevir)
        # Önce Has Fiyat (TRY) -> Hedef Para Birimi kuru bulunur
        try:
            # TRY'den Hedefe geçiş kuru (Örn: 1 TRY = X USD)
            # get_exchange_rate(from, to) mantığı:
            rate_try_to_target = self.cm.get_exchange_rate("TRY", target_curr)
        except:
            rate_try_to_target = 1.0

        price_gold = base_prices_try["gold"] * rate_try_to_target
        price_silver = base_prices_try["silver"] * rate_try_to_target

        report = {
            "details": [],
            "total_gold_pure_gr": 0.0,
            "total_silver_pure_gr": 0.0,
            "total_cash": 0.0,
            "total_debts": 0.0,
            "net_asset_value": 0.0,
            "zakat_due": 0.0,
            "currency": target_curr,
            "is_reached": False,
            "hawl_status": "-"
        }

        # --- 2. ALTIN STOKLARI ---
        for item in self.stock_mgr.get_all():
            if item.quantity <= 0: continue
            
            p_def = self.prod_def_mgr.find_by_attribute('product_name', item.item_type)
            cat = p_def.category if p_def else "Altın"
            karat = p_def.karat_purity if p_def else "22"
            is_silver = "gümüş" in cat.lower() or "gumus" in cat.lower()
            
            gross_gr = item.quantity_gr if (item.quantity_gr and item.quantity_gr > 0) else item.quantity
            purity = self._get_purity_factor(karat, cat)
            pure_gr = gross_gr * purity
            
            unit_price = price_silver if is_silver else price_gold
            val = pure_gr * unit_price
            
            if is_silver: report["total_silver_pure_gr"] += pure_gr
            else: report["total_gold_pure_gr"] += pure_gr
            
            report["details"].append({
                "group": "Gümüş" if is_silver else "Altın",
                "name": item.item_type,
                "karat": f"{karat} ({purity*1000:.0f})",
                "gross": gross_gr,
                "pure": pure_gr,
                "value": val
            })

        # --- 3. ZİYNET STOKLARI ---
        for item in self.ziynet_mgr.get_all():
            if item.quantity <= 0: continue
            
            p_def = self.ziynet_def_mgr.find_by_attribute('product_name', item.item_type)
            gram_per_unit = getattr(p_def, 'default_weight_gr', 0.0) if p_def else 0.0
            
            if gram_per_unit <= 0:
                name_lower = item.item_type.lower()
                if "çeyrek" in name_lower: gram_per_unit = 1.75
                elif "yarım" in name_lower: gram_per_unit = 3.50
                elif "tam" in name_lower: gram_per_unit = 7.00
                elif "ata" in name_lower: gram_per_unit = 7.20
                else: gram_per_unit = 0 
            
            karat = p_def.karat_purity if p_def else "22"
            purity = self._get_purity_factor(karat, "Altın")
            
            total_gross = item.quantity * gram_per_unit
            total_pure = total_gross * purity
            val = total_pure * price_gold
            
            report["total_gold_pure_gr"] += total_pure
            report["details"].append({
                "group": "Ziynet",
                "name": f"{item.item_type} ({int(item.quantity)} Adet)",
                "karat": f"{karat} (x{gram_per_unit}g)",
                "gross": total_gross,
                "pure": total_pure,
                "value": val
            })

        # --- 4. HURDA STOKLARI ---
        for item in self.scrap_mgr.get_all():
            if item.quantity <= 0: continue
            
            p_def = self.scrap_def_mgr.find_by_attribute('product_name', item.item_type)
            cat = p_def.category if p_def else "Altın"
            karat = p_def.karat_purity if p_def else "Hurda"
            
            gross_gr = item.quantity 
            purity = self._get_purity_factor(karat, cat)
            pure_gr = gross_gr * purity
            
            is_silver = "gümüş" in cat.lower() or "gumus" in cat.lower()
            unit_price = price_silver if is_silver else price_gold
            val = pure_gr * unit_price
            
            if is_silver: report["total_silver_pure_gr"] += pure_gr
            else: report["total_gold_pure_gr"] += pure_gr
            
            report["details"].append({
                "group": "Hurda",
                "name": item.item_type,
                "karat": f"{karat}",
                "gross": gross_gr,
                "pure": pure_gr,
                "value": val
            })

        # --- 5. NAKİT VARLIKLAR (DÜZELTME BURADA YAPILDI) ---
        all_accounts = self.main_app.cash_account_manager.get_all() + self.main_app.card_account_manager.get_all()
        for acc in all_accounts:
            mgr = self.main_app.cash_managers.get(acc.id) or self.main_app.card_managers.get(acc.id)
            if mgr:
                balances = mgr.calculate_balance()
                for currency_code, amount in balances.items():
                    if amount > 0.01:
                        # DÜZELTME: Doğrudan canlı kur ile çevir
                        # (Kaynak Para) -> (Hedef Para)
                        exchange_rate = self.cm.get_exchange_rate(currency_code, target_curr)
                        if exchange_rate is None: exchange_rate = 0.0
                        
                        val = amount * exchange_rate
                        
                        report["total_cash"] += val
                        report["details"].append({
                            "group": "Nakit",
                            "name": f"{acc.name}",
                            "karat": currency_code,
                            "gross": amount,
                            "pure": 0,
                            "value": val
                        })

        # --- ALACAKLAR (DÜZELTME UYGULANDI) ---
        receivables = self.main_app.debt_manager.get_debts_by_type("Receivable")
        for r in receivables:
            if not r.is_paid:
                if r.debt_type == "Cash":
                    rem = r.total_amount_base - r.paid_amount_base # Veritabanında genelde Base tutulur ama burası karışık olabilir.
                    # Güvenli yol: orijinal döviz tutarından kalanı bulup çevirmek
                    # Ancak debt_record yapısında kalan orijinal tutar net tutulmuyor olabilir.
                    # Base tutar üzerinden gidelim:
                    
                    # Eğer total_amount_base doğruysa (TRY bazlı kayıtlıysa), bunu hedefe çevir.
                    # Ancak biz dövizli takip yapıyorsak, CurrencyManager'ın çevirisine güvenelim.
                    
                    # Basit yaklaşım: (Orijinal Tutar üzerinden gitmek daha sağlıklı olabilir ama ödemeler base düşülüyor)
                    # Şimdilik base (TRY) kabul edip hedefe çevirelim.
                    
                    # DÜZELTME: Base tutar (TRY) -> Hedef Kur
                    rate_try_to_target = self.cm.get_exchange_rate("TRY", target_curr) or 0.0
                    val = rem * rate_try_to_target
                    
                    report["total_cash"] += val
                    report["details"].append({"group": "Alacak", "name": r.person_full_name, "karat": "-", "gross": 0, "pure": 0, "value": val})

        # --- BORÇLAR (DÜZELTME UYGULANDI) ---
        payables = self.main_app.debt_manager.get_debts_by_type("Payable")
        for p in payables:
            if not p.is_paid:
                if p.debt_type == "Cash":
                    rem = p.total_amount_base - p.paid_amount_base
                    # Base (TRY) -> Hedef Kur
                    rate_try_to_target = self.cm.get_exchange_rate("TRY", target_curr) or 0.0
                    val = rem * rate_try_to_target
                    
                    report["total_debts"] += val
                    report["details"].append({"group": "Borç", "name": p.person_full_name, "karat": "-", "gross": 0, "pure": 0, "value": -val})

        # --- 6. SONUÇ HESAPLAMA ---
        gold_value = report["total_gold_pure_gr"] * price_gold
        silver_value = report["total_silver_pure_gr"] * price_silver
        
        gross_asset_value = gold_value + silver_value + report["total_cash"]
        report["net_asset_value"] = gross_asset_value - report["total_debts"]
        
        # Nisap Kontrolü
        nisap_limit_val = self.NISAP_GOLD_GRAMS * price_gold
        
        if report["net_asset_value"] >= nisap_limit_val:
            report["is_reached"] = True
            report["zakat_due"] = report["net_asset_value"] / 40.0
        
        if nisap_start_date_str:
            try:
                s_date = datetime.strptime(nisap_start_date_str, "%d.%m.%Y")
                days = (datetime.now() - s_date).days
                if days >= 354: report["hawl_status"] = "Yıl Doldu (Farz)"
                else: report["hawl_status"] = f"{354-days} gün kaldı"
            except: report["hawl_status"] = "Tarih Hatalı"
            
        return report

    def calculate_guest_zakat(
        self,
        gold_gr: float = 0.0,
        silver_gr: float = 0.0,
        cash_amount: float = 0.0,
        cash_currency: str = "TRY",
        debts_amount: float = 0.0,
        debts_currency: str = "TRY",
        items: List[Dict[str, Any]] = None,
    ):
        """Müşteri (Misafir) hesaplaması."""
        target_curr = self.main_app.display_currency
        self.cm._fetch_all_rates()
        rates = self.cm.rates_cache
        
        prices = self._get_base_prices(rates)
        
        # TRY -> Hedef Kur
        rate_to_target = self.cm.get_exchange_rate("TRY", target_curr) or 0.0
        
        p_gold = prices["gold"] * rate_to_target
        p_silver = prices["silver"] * rate_to_target
        
        val_gold = 0.0
        val_silver = 0.0
        val_cash = 0.0

        # Yeni çoklu-kalem modeli (Tür -> Ayar/Birim -> Miktar)
        if items:
            for item in items:
                try:
                    amount = float(item.get("amount", 0) or 0)
                except Exception:
                    amount = 0.0
                if amount <= 0:
                    continue

                item_type = str(item.get("type", "cash") or "cash").strip().lower()
                detail = str(item.get("detail", "") or "").strip()

                if item_type in ("gold", "altin", "altın"):
                    purity = self._get_purity_factor(detail or "24", "Altın")
                    pure_gr = amount * purity
                    val_gold += pure_gr * p_gold
                elif item_type in ("silver", "gumus", "gümüş"):
                    purity = self._get_purity_factor(detail or "1000", "Gümüş")
                    pure_gr = amount * purity
                    val_silver += pure_gr * p_silver
                else:
                    currency = detail or cash_currency or target_curr
                    rate_cash = self.cm.get_exchange_rate(currency, target_curr) or 0.0
                    val_cash += amount * rate_cash
        else:
            # Eski tek satırlı model (geriye uyumluluk)
            val_gold = gold_gr * p_gold
            val_silver = silver_gr * p_silver
            rate_cash = self.cm.get_exchange_rate(cash_currency, target_curr) or 0.0
            val_cash = cash_amount * rate_cash
        
        rate_debt = self.cm.get_exchange_rate(debts_currency, target_curr) or 0.0
        val_debt = debts_amount * rate_debt
        
        net = (val_gold + val_silver + val_cash) - val_debt
        nisap_val = self.NISAP_GOLD_GRAMS * p_gold
        
        is_reached = net >= nisap_val
        due = net / 40.0 if is_reached else 0.0
        
        return {
            "val_gold": val_gold, "val_silver": val_silver, "val_cash": val_cash, "val_debt": val_debt,
            "net_assets": net, "nisap_val": nisap_val, "is_reached": is_reached, "zakat_due": due,
            "currency": target_curr
        }




