import sys
import time
import os
import json
import inspect
from pathlib import Path
from datetime import datetime
import base64
import tempfile

from PyQt6.QtWidgets import (QApplication, QMainWindow, QMessageBox,
                             QFileDialog, QProgressBar, QLabel)
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot, QUrl, QVariant, QTimer, QIODevice, QByteArray, QBuffer
from PyQt6.QtGui import QMovie, QPixmap, QClipboard, QImage
from PyQt6.uic import loadUi
from win32com.client import CDispatch, Dispatch

# Proje modüllerini import et
sys.path.append(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()) + "\\..\\..")))
_current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
_project_root = os.path.dirname(os.path.dirname(os.path.dirname(_current_dir)))
sys.path.insert(0, _project_root)
sys.path.insert(0, _current_dir)

from IFikatia import IFikatia
from IGosterim3d import IGosterim3d


class IFikoCikariciDialog(QMainWindow):
    """
    FikoYT Çıkarıcı Dialog - Minimal & Futuristik

    CATIA dökümanlarından aşağıdaki işlemleri gerçekleştirir:
    - WRL (VRML) formatında 3D dosya dışa aktarma
    - Görüntüyü ekranda gösterme
    - Teknik dokümantasyon oluşturma
    - Ağırlık hesaplama
    """

    def __init__(self, parent=None, flags=None, Catia=None):
        """
        Dialog constructor

        Args:
            parent: Parent widget (None - standalone)
            flags: Qt window flags (Qt.WindowType)
            Catia: CATIA COM Application nesnesi
        """
        # CATIA COM nesnesi kontrolü
        if Catia is None:
            raise ValueError("CATIA parametresi boş olamaz!")

        # PyQt6 initialization (super çağrısından önce)
        if not QApplication.instance():
            self.app = QApplication([sys.argv])
        else:
            self.app = QApplication.instance()

        # Default flags ayarla
        if flags is None:
            flags = Qt.WindowType.Window

        # Parent widget olmamalı (standalone dialog)
        super(IFikoCikariciDialog, self).__init__(None)

        # CATIA COM nesnesi sarmalama
        self.__fikatia = IFikatia(obj=Catia)
        self.__dokuman = self.__fikatia.aktifDokuman

        # Seçim değişkenlerini başlat
        self.__aktifEksen = None
        self.__aktifBody = None

        # Script dosyasının yolu
        self.ScriptYolu = str(Path(__file__).parent)

        # Proje kök dizini
        self.ProjeKlasoru = self.__dokuman.klasoru if self.__dokuman else ""

        # .fikoyt gizli klasörü yolu (henüz oluşturulmamış)
        self.FikoytKlasoru = os.path.join(self.ProjeKlasoru, ".fikoyt")

        # PyQt6 UI dosyasını yükle
        try:
            ui_path = os.path.join(self.ScriptYolu, "formAna.ui")
            self.ui = loadUi(ui_path, self)
        except Exception as e:
            QMessageBox.critical(self, "Hata", f"UI dosyası yüklenemedi: {e}")
            self.close()
            return

        # Pencere özelliklerini ayarla
        self.setWindowFlags(
            Qt.WindowType.Window |
            Qt.WindowType.WindowCloseButtonHint |
            Qt.WindowType.CustomizeWindowHint |
            Qt.WindowType.WindowStaysOnTopHint
        )

        self.setWindowTitle("FikoYT")
        self.setGeometry(100, 100, 300, 320)

        # Signal-slot bağlantıları
        self._connect_signals()

        # Başlangıçta UI durumlarını ayarla
        self._update_ui_state()

    def _show_loading(self, show=True, message=""):
        """Loading animasyonu - Artık kullanılmıyor, legacy compatibility için bırakıldı"""
        # Eski loading animasyonu artık kullanılmıyor
        # Tüm loading mesajları artık _update_progress ve statusbar üzerinden yapılıyor
        pass

    def _update_progress(self, current_step, total_steps=5, message=""):
        """Progress bar ve aktif işlem göstergesini güncelle"""
        try:
            # Progress bar güncelle
            if hasattr(self.ui, 'progressIslem'):
                progress_value = int((current_step / total_steps) * 100)
                self.ui.progressIslem.setValue(progress_value)
                self.app.processEvents()

            # Aktif işlem göstergesini güncelle
            if hasattr(self.ui, 'labelAktifIslem'):
                if message:
                    self.ui.labelAktifIslem.setText(f"🔄 {message}")
                    self.ui.labelAktifIslem.setStyleSheet("color: #00d4ff; font-size: 7pt; font-weight: bold; padding: 2px;")
                elif current_step >= total_steps:
                    # Tüm işlemler tamamlandığında
                    self.ui.labelAktifIslem.setText("✅ İşlemler Tamamlandı")
                    self.ui.labelAktifIslem.setStyleSheet("color: #00ff88; font-size: 7pt; font-weight: bold; padding: 2px;")
                else:
                    # Normal durumda
                    self.ui.labelAktifIslem.setText("✅ Hazır")
                    self.ui.labelAktifIslem.setStyleSheet("color: #00d4ff; font-size: 7pt; font-weight: bold; padding: 2px;")

            self.app.processEvents()

        except Exception as e:
            print(f"Progress güncelleme hatası: {e}")

    def _animate_button_state(self, is_processing=True):
        """Buton state'ine göre animasyon ve ikon değişimi ekle"""
        try:
            if hasattr(self.ui, 'btnIslemYap'):
                if is_processing:
                    # İşlem sırasında butonu disable yap ve pause ikonu
                    self.ui.btnIslemYap.setEnabled(False)
                    self.ui.btnIslemYap.setText("⏸️")
                    self.ui.btnIslemYap.setStyleSheet("""
                        QPushButton {
                            background-color: #666666;
                            color: #cccccc;
                            border: 2px solid #555555;
                            border-radius: 6px;
                            font-size: 9pt;
                            font-weight: bold;
                            padding: 2px;
                            outline: none;
                            box-shadow: none;
                        }
                    """)
                else:
                    # İşlem tamamlandı - butonu normal yap ve play ikonu
                    self.ui.btnIslemYap.setEnabled(True)
                    self.ui.btnIslemYap.setText("▶️")
                    self.ui.btnIslemYap.setStyleSheet("""
                        QPushButton {
                            background-color: #00d4ff;
                            color: #0a0e27;
                            border: 2px solid #00d4ff;
                            border-radius: 6px;
                            font-size: 9pt;
                            font-weight: bold;
                            padding: 2px;
                            outline: none;
                        }
                        QPushButton:hover {
                            background-color: #00ffff;
                            border-color: #00ffff;
                        }
                        QPushButton:pressed {
                            background-color: #0099cc;
                            border-color: #0099cc;
                        }
                        QPushButton:!disabled:focus {
                            border-color: #ffffff;
                        }
                    """)

                self.app.processEvents()

        except Exception as e:
            print(f"Buton animasyonu hatası: {e}")

    def _animate_data_update(self, widget, new_value, prefix="", suffix=""):
        """Veri güncellemesi için animasyonlu transition ekle"""
        try:
            if hasattr(widget, 'setText'):
                # Mevcut değeri al
                current_text = widget.text()

                # Yeni animasyonlu değeri ayarla
                if new_value is not None:
                    animated_value = f"{prefix}{new_value}{suffix}"
                else:
                    animated_value = "-"

                widget.setText(animated_value)

                # Flash efekti
                original_style = widget.styleSheet()
                widget.setStyleSheet(f"color: #00ff88; font-weight: bold; {original_style}")

                # Flash efektini geri al (geciktirilmiş)
                QTimer.singleShot(500, lambda: widget.setStyleSheet(original_style))

                self.app.processEvents()

        except Exception as e:
            print(f"Veri animasyonu hatası: {e}")

    def _animate_image_transition(self, image_path, operation="loading"):
        """Resim alanı için transition animasyonu ekle"""
        try:
            if hasattr(self.ui, 'labelResim'):
                if operation == "loading":
                    # Yükleme sırasında gradient efekti
                    self.ui.labelResim.setStyleSheet("""
                        background-color: #1a1f3a;
                        border: 1px solid #00d4ff;
                        border-radius: 3px;
                        color: #555555;
                        font-size: 8pt;
                        background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                            stop:0 #1a1f3a, stop:0.5 #0a0e27, stop:1 #1a1f3a);
                    """)
                    self.ui.labelResim.setText("🖼️ Yükleniyor...")
                elif operation == "success":
                    # Başarılı yükleme - resim kalacak sadece border rengi değişecek
                    self.ui.labelResim.setStyleSheet("""
                        background-color: #1a1f3a;
                        border: 1px solid #00ff88;
                        border-radius: 3px;
                        color: transparent;
                        font-size: 8pt;
                    """)
                    self.ui.labelResim.setText("")  # Metni kaldır
                elif operation == "error":
                    # Hata durumunda
                    self.ui.labelResim.setStyleSheet("""
                        background-color: #1a1f3a;
                        border: 1px solid #ff6b9d;
                        border-radius: 3px;
                        color: #ff6b9d;
                        font-size: 8pt;
                    """)
                    self.ui.labelResim.setText("❌ Hata")

                self.app.processEvents()

        except Exception as e:
            print(f"Resim animasyonu hatası: {e}")

    def _connect_signals(self):
        """PyQt6 signal-slot bağlantılarını kur"""
        # Ana İşlem Butonu
        if hasattr(self.ui, 'btnIslemYap'):
            self.ui.btnIslemYap.clicked.connect(self.islem_yap)

        # Kopyala Butonu
        if hasattr(self.ui, 'btnKopyala'):
            self.ui.btnKopyala.clicked.connect(self._sonuclari_kopyala)

        # Eksen Seçimi Butonları
        if hasattr(self.ui, 'btnEksenSec'):
            self.ui.btnEksenSec.clicked.connect(self._on_btnEksenSec_clicked)
        if hasattr(self.ui, 'btnEksenSil'):
            self.ui.btnEksenSil.clicked.connect(self._on_btnEksenSil_clicked)

        # Body Seçimi Butonları
        if hasattr(self.ui, 'btnBodySec'):
            self.ui.btnBodySec.clicked.connect(self._on_btnBodySec_clicked)
        if hasattr(self.ui, 'btnBodySil'):
            self.ui.btnBodySil.clicked.connect(self._on_btnBodySil_clicked)

        # Malzeme ve Yoğunluk Senkronizasyonu
        if hasattr(self.ui, 'comboMalzeme'):
            self.ui.comboMalzeme.currentTextChanged.connect(self._on_comboMalzeme_changed)

        if hasattr(self.ui, 'spinYogunluk'):
            self.ui.spinYogunluk.valueChanged.connect(self._on_spinYogunluk_changed)

    def _sonuclari_kopyala(self):
        """Sonuçları ve resmi renkli, kaliteli formatında clipboard'a kopyala"""
        try:
            # Gerekli bilgileri al
            dosya_ismi = self.ui.labelDosyaIsmi.text().replace("📁 ", "")
            agirlik_text = self.ui.labelAgirlik.text().replace("⚖️ ", "")
            olculer_text = self.ui.labelOlculer.text().replace("📐 ", "")

            # Eğer boş değerler varsa varsayılan değerler ata
            if dosya_ismi == "-" or dosya_ismi == "":
                dosya_ismi = "Bilinmeyen Dosya"
            if agirlik_text == "-" or agirlik_text == "":
                agirlik_text = "Hesaplanamadı"
            if olculer_text == "X:- Y:- Z:-" or olculer_text == "":
                olculer_text = "X:- Y:- Z:-"

            # Hem metin hem de resmi içeren kopyalama
            self._copy_with_image(dosya_ismi, olculer_text, agirlik_text)

            # Kullanıcıya bildirim
            self.ui.statusBar().showMessage("✅ Sonuçlar ve resim kopyalandı!")
            QTimer.singleShot(3000, lambda: self.ui.statusBar().clearMessage())

            print(f"[DEBUG] Clipboard içeriği ve resim kopyalandı")

        except Exception as e:
            print(f"[ERROR] Kopyalama hatası: {e}")
            self.ui.statusBar().showMessage(f"❌ Kopyalama hatası: {str(e)}")
            QTimer.singleShot(3000, lambda: self.ui.statusBar().clearMessage())

    def _copy_with_image(self, dosya_ismi, olculer_text, agirlik_text):
        """Resim ve metni birlikte yüksek kaliteli şekilde clipboard'a kopyala"""
        try:
            clipboard = QApplication.clipboard()

            # Önce metin clipboard'a yaz (fallback olarak)
            text_content = f"""{dosya_ismi}
{olculer_text} | Ağırlık: {agirlik_text}"""
            clipboard.setText(text_content, QClipboard.Mode.Clipboard)

            # Resmi clipboard'a kopyalamaya çalış
            if hasattr(self.ui, 'labelResim') and self.ui.labelResim.pixmap():
                pixmap = self.ui.labelResim.pixmap()
                if not pixmap.isNull():
                    # Resmi yüksek kalitede işlemek için orijinal resmi al
                    image = pixmap.toImage()

                    # Eğer resim çok küçükse, orijinal boyutunu koru
                    if image.width() < 800:
                        # Daha yüksek çözünürlük için resmi ölçekle
                        image = image.scaled(1200, 800, Qt.AspectRatioMode.KeepAspectRatio,
                                           Qt.TransformationMode.SmoothTransformation)

                    # Resmi yüksek kaliteli JPEG olarak kaydet
                    byte_array = QByteArray()
                    buffer = QBuffer(byte_array)
                    buffer.open(QIODevice.OpenModeFlag.WriteOnly)

                    # Yüksek kaliteli JPEG (90 kalite)
                    image.save(buffer, "JPG", 90)
                    buffer.close()

                    base64_data = byte_array.toBase64().data().decode('utf-8')

                    # HTML formatında içerik oluştur (renkli ve profesyonel)
                    html_content = self._create_html_with_image(
                        base64_data, dosya_ismi, olculer_text, agirlik_text
                    )

                    # HTML clipboard formatunu ayarla
                    mime_data = clipboard.mimeData()
                    if mime_data:
                        mime_data.setHtml(html_content)

                        # Yüksek kaliteli resmi ekle (JPEG olarak)
                        mime_data.setData("image/jpeg", byte_array.data() if isinstance(byte_array, QByteArray) else byte_array)

                        # Başlık ve açıklama bilgileri
                        mime_data.setData("text/plain", text_content)

                        # Resim başlıkları
                        mime_data.setText(f"FikoYT Dokümantasyon - {dosya_ismi}")

                        clipboard.setMimeData(mime_data)

        except Exception as e:
            print(f"[ERROR] Resim kopyalama hatası: {e}")
            # Eğer resim kopyalanamazsa sadece metinle devam et

    def _update_ui_state(self):
        """UI durumlarını güncelle (buton aktif/pasif durumları)"""
        try:
            # Eksen ve body seçim durumuna göre UI'ı güncelle
            eksen_secili = self.__aktifEksen is not None
            body_secili = self.__aktifBody is not None

            # Buton durumlarını güncelle
            if hasattr(self.ui, 'textEksen'):
                self.ui.textEksen.setText(
                    self.__aktifEksen.ismi if self.__aktifEksen else "Eksen seçilmedi"
                )
                # Border rengini seçim durumuna göre değiştir
                if eksen_secili:
                    self.ui.textEksen.setStyleSheet("background-color: #1a1f3a; border: 1px solid #00ff88; border-radius: 2px; color: #ffffff; font-size: 8pt; padding: 2px;")
                else:
                    self.ui.textEksen.setStyleSheet("background-color: #1a1f3a; border: 1px solid #666666; border-radius: 2px; color: #ffffff; font-size: 8pt; padding: 2px;")

            if hasattr(self.ui, 'textBody'):
                self.ui.textBody.setText(
                    self.__aktifBody.ismi if self.__aktifBody else "Body seçilmedi"
                )
                # Border rengini seçim durumuna göre değiştir
                if body_secili:
                    self.ui.textBody.setStyleSheet("background-color: #1a1f3a; border: 1px solid #00ff88; border-radius: 2px; color: #ffffff; font-size: 8pt; padding: 2px;")
                else:
                    self.ui.textBody.setStyleSheet("background-color: #1a1f3a; border: 1px solid #666666; border-radius: 2px; color: #ffffff; font-size: 8pt; padding: 2px;")

            self.app.processEvents()

        except Exception as e:
            print(f"[ERROR] UI durum güncelleme hatası: {e}")

    @property
    def aktifEksen(self):
        """Aktif eksen nesnesi"""
        return self.__aktifEksen

    @aktifEksen.setter
    def aktifEksen(self, value):
        """Aktif eksen nesnesini ayarla"""
        self.__aktifEksen = value
        self._update_ui_state()
        print(f"[DEBUG] Aktif eksen güncellendi: {value.ismi if value else 'None'}")

    @aktifEksen.deleter
    def aktifEksen(self):
        """Aktif eksen nesnesini temizle"""
        self.__aktifEksen = None
        self._update_ui_state()
        print("[DEBUG] Aktif eksen temizlendi")

    @property
    def aktifBody(self):
        """Aktif body nesnesi"""
        return self.__aktifBody

    @aktifBody.setter
    def aktifBody(self, value):
        """Aktif body nesnesini ayarla"""
        self.__aktifBody = value
        self._update_ui_state()
        print(f"[DEBUG] Aktif body güncellendi: {value.ismi if value else 'None'}")

    @aktifBody.deleter
    def aktifBody(self):
        """Aktif body nesnesini temizle"""
        self.__aktifBody = None
        self._update_ui_state()
        print("[DEBUG] Aktif body temizlendi")

    def _on_btnEksenSec_clicked(self):
        """Eksen seçme butonu tıklandığında çağrılır"""
        try:
            self.setVisible(False)
            secililer = self.__dokuman.secililer
            self.__fikatia.aktifEt()
            durum = secililer.sec2(["AxisSystem"], Mesaj="Lütfen Eksen Seçiniz")
            if durum == "Normal":
                # Seçilen nesneyi doğrudan IEksen olarak sakla
                catia_eksen = secililer.item2(0).nesne
                from IEksen import IEksen
                self.aktifEksen = IEksen(obj=catia_eksen.catNesne, sahip=self.__fikatia)
                self.__fikatia.durumCubugu = f"Eksen seçildi: {self.aktifEksen.ismi}"
            else:
                self.__fikatia.durumCubugu = "Seçim İptal Edildi"
                self.aktifEksen = None  # Temizle
            self.setVisible(True)
            print("[DEBUG] Eksen seçme işlemi tamamlandı")
        except Exception as e:
            print(f"[ERROR] Eksen seçme hatası: {e}")
            self.__fikatia.durumCubugu = f"Hata: {str(e)}"
            self.setVisible(True)

    def _on_btnEksenSil_clicked(self):
        """Eksi temizle butonu tıklandığında çağrılır"""
        try:
            self.aktifEksen = None
            self.__fikatia.durumCubugu = "Eksen temizlendi"
            print("[DEBUG] Eksen temizlendi")
        except Exception as e:
            print(f"[ERROR] Eksen temizleme hatası: {e}")

    def _on_btnBodySec_clicked(self):
        """Body seçme butonu tıklandığında çağrılır"""
        try:
            self.setVisible(False)
            secililer = self.__dokuman.secililer
            self.__fikatia.aktifEt()
            durum = secililer.sec2(["HybridBody", "Body"], Mesaj="Lütfen Body Seçiniz")
            if durum == "Normal":
                self.aktifBody = secililer.item2(0).nesne
                self.__fikatia.durumCubugu = f"Body seçildi: {self.aktifBody.ismi}"
            else:
                self.__fikatia.durumCubugu = "Seçim İptal Edildi"
                self.aktifBody = None  # Temizle
            self.setVisible(True)
            print("[DEBUG] Body seçme işlemi tamamlandı")
        except Exception as e:
            print(f"[ERROR] Body seçme hatası: {e}")
            self.__fikatia.durumCubugu = f"Hata: {str(e)}"
            self.setVisible(True)

    def _on_btnBodySil_clicked(self):
        """Body temizle butonu tıklandığında çağrılır"""
        try:
            self.aktifBody = None
            self.__fikatia.durumCubugu = "Body temizlendi"
            print("[DEBUG] Body temizlendi")
        except Exception as e:
            print(f"[ERROR] Body temizleme hatası: {e}")

    def _create_html_with_image(self, base64_data, dosya_ismi, olculer_text, agirlik_text):
        """HTML formatında içerik oluştur (renkli ve profesyonel)"""
        try:
            # Boyutları ve renkleri formatla (kalın ve koyu renkli)
            try:
                olculer_parts = olculer_text.replace("X:", "").replace("Y:", "").replace("Z:", "").split()
                if len(olculer_parts) >= 3:
                    x_val, y_val, z_val = olculer_parts[0], olculer_parts[1], olculer_parts[2]
                    # Farklı koyu renkler
                    olculer_colored = f'<span style="color: #8B4513; font-weight: bold;">X:{x_val}</span> <span style="color: #2F4F4F; font-weight: bold;">Y:{y_val}</span> <span style="color: #800080; font-weight: bold;">Z:{z_val}</span>'
                else:
                    olculer_colored = f'<span style="color: #2c3e50; font-weight: bold;">{olculer_text}</span>'
            except:
                olculer_colored = f'<span style="color: #2c3e50; font-weight: bold;">{olculer_text}</span>'
            try:
                if "Hesaplanamadı" in agirlik_text:
                    agirlik_colored = f'<span style="color: #2c3e50; font-weight: bold;">⚖️ Ağırlık: {agirlik_text.replace("⚖️ ", "")}</span>'
                else:
                    agirlik_colored = f'<span style="color: #2c3e50; font-weight: bold;">⚖️ Ağırlık: {agirlik_text.replace("⚖️ ", "")}</span>'
            except:
                agirlik_colored = f'<span style="color: #2c3e50; font-weight: bold;">⚖️ Ağırlık: {agirlik_text.replace("⚖️ ", "")}</span>'

            # HTML formatı oluştur (Minimal inline style - Word için)
            html_content = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<div style="font-family: 'Segoe UI', Arial, sans-serif; padding: 15px; background: linear-gradient(135deg, #0a0e27 0%, #1a1f3a 100%); border: 2px solid #00d4ff; box-shadow: 0 0 20px rgba(0,212,255,0.3);">
    <img src="data:image/jpeg;base64,{base64_data}" alt="{dosya_ismi}" style="width: 100%; max-width: 800px; display: block; margin: 0 auto 15px; border: 2px solid #00d4ff; box-shadow: 0 0 15px rgba(0,212,255,0.5);"/>
    <p style="margin: 0; padding: 8px; font-size: 9pt; font-weight: 600; text-align: center; background: rgba(0,0,0,0.4); border-radius: 4px;">
        <span>📁 <span  style="color: teal; text-shadow: 0 0 8px rgba(0,212,255,0.8);">{dosya_ismi.rsplit('.', 1)[0]}</span></span>
        <span style="color: #888; margin: 0 8px;">|</span>
        <span>📐<span  style="color: red; text-shadow: 0 0 8px rgba(255,107,157,0.8);"> X: {f"{float(olculer_parts[0]):.3f}" if len(olculer_parts) > 0 and olculer_parts[0] != '-' else '---'}</span>
        <span style="color: green; text-shadow: 0 0 8px rgba(0,255,136,0.8); margin-left: 5px;">Y: {f"{float(olculer_parts[1]):.3f}" if len(olculer_parts) > 1 and olculer_parts[1] != '-' else '---'}</span>
        <span style="color: teal; text-shadow: 0 0 8px rgba(0,212,255,0.8); margin-left: 5px;">Z: {f"{float(olculer_parts[2]):.3f}" if len(olculer_parts) > 2 and olculer_parts[2] != '-' else '---'}</span></span>
        <span style="color: #888; margin: 0 8px;">|</span>
        <span>⚖️ <span  style="color: blue; text-shadow: 0 0 8px rgba(255,0,255,0.8);">{agirlik_text.replace('⚖️ Ağırlık: ', '').replace('⚖️ ', '') if agirlik_text else '-'}</span></span>
    </p>
</div>
</body>
</html>"""

            return html_content

        except Exception as e:
            print(f"[ERROR] HTML oluşturma hatası: {e}")
            # Eğer HTML oluşturulamazsa basit metinle devam et
            return f"""{dosya_ismi}
{olculer_text} | Ağırlık: {agirlik_text}"""

    def _on_comboMalzeme_changed(self, malzeme_text):
        """
        ComboBox malzeme seçimi değiştiğinde SpinBox'ı güncelle
        """
        try:
            # Malzeme-Yoğunluk eşleştirmesi
            malzemeler = {
                "Alm 2710": 2710,
                "Zamak 6710": 6710,
                "Çelik 7850": 7850,
                "P.Çelik 8000": 8000,
                "Bakır 8960": 8960,
                "Titanyum 4500": 4500,
                "ABS 1040": 1040,
                "PLA 1200": 1200,
                "Mg 1800": 1800,
                "Ni 8902": 8902,
                "Pirinç 8470": 8470,
                "Bronz 8700": 8700,
                "Fe 7874": 7874,
                "Al2O3 3950": 3950
            }

            # Seçilen malzemenin yoğunluğunu al
            yogunluk = malzemeler.get(malzeme_text, 2710)

            # SpinBox'ı güncelle (signal döngüsünü engellemek için blockedSignals kullan)
            if hasattr(self.ui, 'spinYogunluk'):
                self.ui.spinYogunluk.blockSignals(True)
                self.ui.spinYogunluk.setValue(int(yogunluk))
                self.ui.spinYogunluk.blockSignals(False)

            print(f"[DEBUG] Malzeme seçildi: {malzeme_text}, Yoğunluk: {yogunluk}")

        except Exception as e:
            print(f"[ERROR] Malzeme değişim hatası: {e}")

    def _on_spinYogunluk_changed(self, yogunluk_degeri):
        """
        SpinBox yoğunluk değeri değiştiğinde ComboBox'ı güncelle
        """
        try:
            # Ters Malzeme-Yoğunluk eşleştirmesi
            yogunluk_to_malzeme = {
                2710: "Alm 2710",
                6710: "Zamak 6710",
                7850: "Çelik 7850",
                8000: "P.Çelik 8000",
                8960: "Bakır 8960",
                4500: "Titanyum 4500",
                1040: "ABS 1040",
                1200: "PLA 1200",
                1800: "Mg 1800",
                8902: "Ni 8902",
                8470: "Pirinç 8470",
                8700: "Bronz 8700",
                7874: "Fe 7874",
                3950: "Al2O3 3950"
            }

            # Değeri tam sayı olarak kontrol et
            yogunluk_int = int(yogunluk_degeri)

            # Eğer değer eşleşiyorsa ComboBox'ı güncelle
            if yogunluk_int in yogunluk_to_malzeme:
                malzeme_adi = yogunluk_to_malzeme[yogunluk_int]

                # ComboBox'ı güncelle (signal döngüsünü engellemek için blockedSignals kullan)
                if hasattr(self.ui, 'comboMalzeme'):
                    self.ui.comboMalzeme.blockSignals(True)
                    # İlgili öğeyi bul ve seç
                    for i in range(self.ui.comboMalzeme.count()):
                        if self.ui.comboMalzeme.itemText(i) == malzeme_adi:
                            self.ui.comboMalzeme.setCurrentIndex(i)
                            break
                    self.ui.comboMalzeme.blockSignals(False)

                print(f"[DEBUG] Yoğunluk değişti: {yogunluk_int}, Malzeme: {malzeme_adi}")
            else:
                # Özel bir değer girilmişse, ComboBox'ı "Özel" olarak işaretle
                print(f"[DEBUG] Özel yoğunluk değeri: {yogunluk_int}")

        except Exception as e:
            print(f"[ERROR] Yoğunluk değişim hatası: {e}")

    def _malzeme_yogunluk_al(self):
        """
        SpinBox'tan mevcut yoğunluk değerini al (ComboBox'tan veya kullanıcı girişinden)

        Returns:
            float: Mevcut yoğunluk değeri (kg/m³)
        """
        try:
            # Öncelikle SpinBox değerini al
            if hasattr(self.ui, 'spinYogunluk'):
                yogunluk = self.ui.spinYogunluk.value()
            else:
                # Fallback: ComboBox'tan al (eski mantık)
                malzemeler = {
                    "Alm 2710": 2710,
                    "Zamak 6710": 6710,
                    "Çelik 7850": 7850,
                    "P.Çelik 8000": 8000,
                    "Bakır 8960": 8960,
                    "Titanyum 4500": 4500,
                    "ABS 1040": 1040,
                    "PLA 1200": 1200,
                    "Mg 1800": 1800,
                    "Ni 8902": 8902,
                    "Pirinç 8470": 8470,
                    "Bronz 8700": 8700,
                    "Fe 7874": 7874,
                    "Al2O3 3950": 3950
                }
                secilen_text = self.ui.comboMalzeme.currentText()
                yogunluk = malzemeler.get(secilen_text, 2710)

            print(f"[DEBUG] Kullanılan yoğunluk: {yogunluk} kg/m³")
            return yogunluk

        except Exception as e:
            print(f"[ERROR] Yoğunluk alma hatası: {e}")
            return 2710  # Varsayılan değer

    def _part_agirlik_hesapla(self, doc_com, yogunluk):
        """
        Part dokümanı için ağırlık hesapla
        """
        try:
            part_com = doc_com.Part
            hacim = 0.0

            # SPAWorkbench ile SADECE SEÇİLEN BODY'nin hacmini al
            try:
                spa_workbench = doc_com.GetWorkbench("SPAWorkbench")

                # Seçili Body varsa onu kullan, yoksa ilk Body'yi kullan
                if self.__aktifBody:
                    # Kullanıcının seçtiği özel Body'yi kullan
                    body_com = self.__aktifBody.catNesne
                    print(f"[DEBUG] Seçili Body kullanılıyor: {self.__aktifBody.ismi}")

                    try:
                        body_ref = part_com.CreateReferenceFromObject(body_com)
                        measurable = spa_workbench.GetMeasurable(body_ref)
                        hacim = measurable.Volume
                        print(f"[DEBUG] Seçili Body Volume = {hacim} m³")
                    except Exception as e:
                        print(f"[DEBUG] Seçili Body hacim hesaplama hatası: {e}")
                        hacim = 0.0

                elif hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                    # Body seçilmemişse TÜM Body'lerin hacmini topla
                    bodies = part_com.Bodies
                    hacim = 0.0
                    print(f"[DEBUG] Body seçilmemiş, tüm {bodies.Count} Body'nin hacmi toplanıyor")

                    for i in range(1, bodies.Count + 1):
                        try:
                            body = bodies.Item(i)
                            body_ref = part_com.CreateReferenceFromObject(body)
                            measurable = spa_workbench.GetMeasurable(body_ref)
                            body_vol = measurable.Volume
                            hacim += body_vol
                            print(f"[DEBUG] Body {i} ({body.Name}) Volume = {body_vol} m³")
                        except Exception as e:
                            print(f"[DEBUG] Body {i} hacim hesaplama hatası: {e}")

                    print(f"[DEBUG] Tüm Body'lerin toplam hacmi = {hacim} m³")

                if hacim > 0:
                    print(f"[DEBUG] Kullanılan hacim = {hacim} m³")

            except Exception as e:
                print(f"[DEBUG] SPAWorkbench hatası: {e}")
                # Fallback: Part'ın toplam hacmini kullan (son çare)
                if hasattr(part_com, 'Volume'):
                    hacim = part_com.Volume
                    print(f"[DEBUG] Fallback - part_com.Volume = {hacim}")

            # Ağırlık hesapla
            if hacim and yogunluk:
                agirlik = hacim * yogunluk
                body_adi = self.__aktifBody.ismi if self.__aktifBody else "Tüm Body'ler"
                print(f"[DEBUG] {body_adi} için hesaplanan ağırlık = {agirlik} kg")
                return agirlik

        except Exception as e:
            print(f"[DEBUG] Part ağırlık hesaplama hatası: {e}")

        return None

    def _product_agirlik_hesapla(self, doc_com, yogunluk):
        """
        Product dokümanı için içindeki Part'ların ağırlığını hesapla
        """
        try:
            # Önce IProduct wrapper'ını kullanmayı dene
            try:
                # IProduct sınıfını import et
                sys.path.insert(0, _project_root)
                from IProduct import IProduct

                # Doğru Product nesnesini bul
                product_com = None

                # 1. doc_com.Product kontrolü
                if hasattr(doc_com, 'Product'):
                    product_com = doc_com.Product
                    print(f"[DEBUG] doc_com.Product bulundu")

                # 2. doc_com'un kendisi Product mi kontrolü
                elif hasattr(doc_com, 'Products'):
                    product_com = doc_com
                    print(f"[DEBUG] doc_com kendisi Product")

                # 3. Application üzerinden dene
                elif hasattr(doc_com, 'Application'):
                    try:
                        active_doc = doc_com.Application.ActiveDocument
                        if hasattr(active_doc, 'Product'):
                            product_com = active_doc.Product
                        elif hasattr(active_doc, 'Products'):
                            product_com = active_doc
                        print(f"[DEBUG] Application üzerinden Product bulundu")
                    except:
                        pass

                if not product_com:
                    print(f"[DEBUG] Product nesnesi bulunamadı")
                    return None

                # IProduct wrapper'ı oluştur
                product_wrapper = IProduct(obj=product_com, sahip=None)
                print(f"[DEBUG] IProduct wrapper oluşturuldu")

                # Product'ın içindeki ürünleri IProductlar ile al
                products = product_wrapper.productlar
                product_count = products.sayisi
                print(f"[DEBUG] IProductlar ile {product_count} ürün bulundu")

                if product_count == 0:
                    print(f"[DEBUG] Product içinde alt ürün bulunamadı")
                    return None

                toplam_hacim = 0.0
                toplam_agirlik = 0.0
                part_sayisi = 0

                print(f"[DEBUG] Product içindeki Part'lar IProduct ile taranıyor...")

                # Tüm ürünleri tara
                for i in range(product_count):
                    try:
                        item = products.item(i)
                        print(f"[DEBUG] İşleniyor: Product {i+1}/{product_count}")

                        # Eğer bu bir Part ise
                        if item.partMi:
                            part_sayisi += 1
                            print(f"[DEBUG]   ✓ Part bulundu: {item.parcaNumarasi} - {item.ismi}")

                            # Part'ın ReferansProduct'ını al
                            try:
                                ref_product = item.referansProduct
                                print(f"[DEBUG]   - ReferansProduct: {ref_product.parcaNumarasi}")

                                # ReferansProduct üzerinden Part belgesine eriş
                                part_doc = None
                                if hasattr(ref_product, 'dokuman'):
                                    part_doc = ref_product.dokuman
                                    print(f"[DEBUG]   - Part dokümanı bulundu")
                                else:
                                    # Alternatif: Part'ın catNesne'sini kullan
                                    try:
                                        if hasattr(ref_product, 'catNesne'):
                                            cat_obj = ref_product.catNesne
                                            # GetTechnologicalObject ile Part'ı bul
                                            part_obj = cat_obj.GetTechnologicalObject("Part")
                                            if part_obj:
                                                part_doc = type('PartDoc', (), {'catNesne': part_obj})()
                                                print(f"[DEBUG]   - GetTechnologicalObject ile Part bulundu")
                                    except:
                                        pass

                                if part_doc:
                                    # Part'ı mevcut product'a ekle ve işle
                                    try:
                                        part_hacim, part_agirlik = self._mevcut_producta_part_ekle(item, yogunluk)
                                        if part_hacim > 0:
                                            toplam_hacim += part_hacim
                                            toplam_agirlik += part_agirlik
                                            print(f"[DEBUG]   ✓ Part hacmi = {part_hacim:.6f} m³, ağırlık = {part_agirlik:.3f} kg")
                                        else:
                                            print(f"[DEBUG]   - Mevcut product ile hacim alınamadı, fallback deneniyor")
                                            # Fallback: Eski yöntemle dene
                                            part_hacim = self._part_dokumanindan_hacim_al(part_doc, yogunluk)
                                            if part_hacim > 0:
                                                toplam_hacim += part_hacim
                                                part_agirlik = part_hacim * yogunluk
                                                toplam_agirlik += part_agirlik
                                                print(f"[DEBUG]   - Eski yöntemle hacim = {part_hacim:.6f} m³, ağırlık = {part_agirlik:.3f} kg")

                                    except Exception as e:
                                        print(f"[DEBUG]   - Mevcut product hatası: {e}")
                                        # Son çare: Eski yöntem
                                        part_hacim = self._part_dokumanindan_hacim_al(part_doc, yogunluk)
                                        if part_hacim > 0:
                                            toplam_hacim += part_hacim
                                            part_agirlik = part_hacim * yogunluk
                                            toplam_agirlik += part_agirlik
                                else:
                                    print(f"[DEBUG]   ✗ Part dokümanı bulunamadı")

                            except Exception as e:
                                print(f"[DEBUG]   - ReferansProduct işleme hatası: {e}")
                                # Son çare: Product'ın kendisinden hacmi almayı dene
                                try:
                                    part_hacim = self._product_hacmini_hesapla(item)
                                    if part_hacim > 0:
                                        toplam_hacim += part_hacim
                                        part_agirlik = part_hacim * yogunluk
                                        toplam_agirlik += part_agirlik
                                        part_sayisi += 1
                                        print(f"[DEBUG]   - Product'tan direk hacim alındı = {part_hacim:.6f} m³")
                                except Exception as e2:
                                    print(f"[DEBUG]   - Direkt hacim alma başarısız: {e2}")

                        else:
                            print(f"[DEBUG]   - Bu bir Product: {item.parcaNumarasi} - {item.ismi}")

                    except Exception as e:
                        print(f"[DEBUG] Product {i+1} işlenemedi: {e}")

                print(f"[DEBUG] Product özeti: {part_sayisi} Part, Toplam hacim = {toplam_hacim:.6f} m³, Toplam ağırlık = {toplam_agirlik:.3f} kg")
                return toplam_agirlik if toplam_agirlik > 0 else None

            except ImportError as e:
                print(f"[DEBUG] IProduct import hatası: {e}")
                return None

        except Exception as e:
            print(f"[ERROR] Product ağırlık hesaplama hatası: {e}")
            import traceback
            traceback.print_exc()
            return None

    def _part_dokumanindan_hacim_al(self, part_doc, yogunluk):
        """
        Part dokümanından hacmi al (mevcut Part mantığıyla)
        """
        try:
            # Part'ın catNesne'sini al
            part_com = part_doc.catNesne if hasattr(part_doc, 'catNesne') else part_doc

            if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                # SPAWorkbench ile hacmi hesapla
                try:
                    # SPAWorkbench'i al
                    if hasattr(self.__dokuman, 'catNesne'):
                        spa_workbench = self.__dokuman.catNesne.GetWorkbench("SPAWorkbench")
                    else:
                        # Alternatif yöntemler dene
                        spa_workbench = part_com.GetWorkbench("SPAWorkbench")

                    toplam_hacim = 0.0
                    bodies = part_com.Bodies

                    for i in range(1, bodies.Count + 1):
                        try:
                            body = bodies.Item(i)
                            body_ref = part_com.CreateReferenceFromObject(body)
                            measurable = spa_workbench.GetMeasurable(body_ref)
                            body_vol = measurable.Volume
                            toplam_hacim += body_vol
                        except:
                            pass

                    return toplam_hacim

                except Exception as e:
                    print(f"[DEBUG] SPAWorkbench hacim hesaplama hatası: {e}")

            # Fallback: Part'ın Volume özelliğini kullan
            if hasattr(part_com, 'Volume'):
                return part_com.Volume

        except Exception as e:
            print(f"[DEBUG] Part dokümanı hacim alma hatası: {e}")

        return 0.0

    def _product_hacmini_hesapla(self, product):
        """
        Product'ın kendisinden direk hacim hesapla (son çare)
        """
        try:
            # Product'ın catNesne'sini al
            prod_com = product.catNesne if hasattr(product, 'catNesne') else product

            # SPAWorkbench ile hacmi ölç
            try:
                spa_workbench = prod_com.GetWorkbench("SPAWorkbench")
                ref = prod_com.CreateReferenceFromObject(prod_com)
                measurable = spa_workbench.GetMeasurable(ref)
                return measurable.Volume
            except:
                pass

            # Fallback: Volume özelliğini kontrol et
            if hasattr(prod_com, 'Volume'):
                return prod_com.Volume

        except:
            pass

        return 0.0

    def _part_bounding_box_hesapla(self, part_doc):
        """
        Part dokümanının bounding box'ını hesapla
        Returns: (min_x, min_y, min_z, max_x, max_y, max_z) or None
        """
        try:
            # Part'ın catNesne'sini al
            part_com = part_doc.catNesne if hasattr(part_doc, 'catNesne') else part_doc

            if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                # SPAWorkbench'i al
                spa_workbench = None
                try:
                    if hasattr(self.__dokuman, 'catNesne'):
                        spa_workbench = self.__dokuman.catNesne.GetWorkbench("SPAWorkbench")
                    else:
                        spa_workbench = part_com.GetWorkbench("SPAWorkbench")
                except:
                    pass

                if not spa_workbench:
                    return None

                min_x, min_y, min_z = float('inf'), float('inf'), float('inf')
                max_x, max_y, max_z = float('-inf'), float('-inf'), float('-inf')

                bodies = part_com.Bodies

                for i in range(1, bodies.Count + 1):
                    try:
                        body = bodies.Item(i)
                        body_ref = part_com.CreateReferenceFromObject(body)
                        measurable = spa_workbench.GetMeasurable(body_ref)

                        # BoundingBox almayı dene
                        try:
                            if hasattr(measurable, 'GetBoundingBox'):
                                bbox = measurable.GetBoundingBox()
                                if bbox and len(bbox) >= 6:
                                    min_x = min(min_x, bbox[0])
                                    min_y = min(min_y, bbox[1])
                                    min_z = min(min_z, bbox[2])
                                    max_x = max(max_x, bbox[3])
                                    max_y = max(max_y, bbox[4])
                                    max_z = max(max_z, bbox[5])
                            else:
                                # COG kullanarak yaklaşık bbox oluştur
                                cog = (0.0, 0.0, 0.0)
                                measurable.GetCOG(cog)
                                tolerance = 0.01  # 10mm
                                min_x = min(min_x, cog[0] - tolerance)
                                min_y = min(min_y, cog[1] - tolerance)
                                min_z = min(min_z, cog[2] - tolerance)
                                max_x = max(max_x, cog[0] + tolerance)
                                max_y = max(max_y, cog[1] + tolerance)
                                max_z = max(max_z, cog[2] + tolerance)
                        except:
                            pass

                    except:
                        pass

                if min_x != float('inf'):
                    return (min_x, min_y, min_z, max_x, max_y, max_z)

        except:
            pass

        return None

    def _part_dosya_yolu_bul(self, item):
        """
        IProduct öğesinin Part dosya yolunu bul - Tüm CATIA yöntemleri
        """
        try:
            print(f"[DEBUG] Part dosya yolu aranıyor: {item.parcaNumarasi} - {item.ismi}")

            # 1. item.dokuman üzerinden dene (numokratör sistemi)
            if hasattr(item, 'dokuman') and item.dokuman:
                print(f"[DEBUG] 1. item.dokuman kontrol ediliyor...")
                if hasattr(item.dokuman, 'tamIsmi') and item.dokuman.tamIsmi:
                    path = item.dokuman.tamIsmi
                    print(f"[DEBUG]   - item.dokuman.tamIsmi: {path}")
                    if path.endswith('.CATPart'):
                        return path
                elif hasattr(item.dokuman, 'klasoru'):
                    # CATPart uzantısı ile dosya adını oluştur
                    dosya_adi = f"{item.parcaNumarasi}.CATPart"
                    path = os.path.join(item.dokuman.klasoru, dosya_adi)
                    print(f"[DEBUG]   - item.dokuman.klasoru + dosya adı: {path}")
                    return path

            # 2. ReferansProduct üzerinden dene
            if hasattr(item, 'referansProduct') and item.referansProduct:
                print(f"[DEBUG] 2. referansProduct kontrol ediliyor...")
                ref_product = item.referansProduct
                if hasattr(ref_product, 'dokuman') and ref_product.dokuman:
                    if hasattr(ref_product.dokuman, 'tamIsmi') and ref_product.dokuman.tamIsmi:
                        path = ref_product.dokuman.tamIsmi
                        print(f"[DEBUG]   - ref_product.dokuman.tamIsmi: {path}")
                        if path.endswith('.CATPart'):
                            return path
                    elif hasattr(ref_product.dokuman, 'klasoru'):
                        dosya_adi = f"{item.parcaNumarasi}.CATPart"
                        path = os.path.join(ref_product.dokuman.klasoru, dosya_adi)
                        print(f"[DEBUG]   - ref_product.dokuman.klasoru + dosya adı: {path}")
                        return path

            # 3. CATIA'nın tüm path özelliklerini kontrol et
            print(f"[DEBUG] 3. CATIA path özellikleri kontrol ediliyor...")
            try:
                if hasattr(item, 'catNesne'):
                    cat_obj = item.catNesne
                    path_attrs = [
                        'ReferencePath', 'Path', 'FullPath',
                        'ReferenceFile', 'File', 'Location',
                        'Source', 'DocumentPath'
                    ]

                    for attr in path_attrs:
                        if hasattr(cat_obj, attr):
                            try:
                                path = getattr(cat_obj, attr)
                                print(f"[DEBUG]   - {attr}: {path}")
                                if path and isinstance(path, str):
                                    if path.endswith('.CATPart'):
                                        return path
                                    elif not '.' in path:
                                        # Uzantısı yoksa CATPart ekle
                                        return f"{path}.CATPart"
                            except:
                                pass

            except Exception as e:
                print(f"[DEBUG]   - CATIA özellikleri hatası: {e}")

            # 4. CATIA'nın bağlı olduğu dokümanı kontrol et
            try:
                if hasattr(item, 'catNesne'):
                    cat_obj = item.catNesne
                    # ParentDocument veya Document özellikleri
                    parent_attrs = ['ParentDocument', 'Document', 'AssociatedFile']
                    for attr in parent_attrs:
                        if hasattr(cat_obj, attr):
                            try:
                                parent = getattr(cat_obj, attr)
                                if hasattr(parent, 'FullName'):
                                    path = parent.FullName
                                    print(f"[DEBUG]   - {attr}.FullName: {path}")
                                    if path and path.endswith('.CATPart'):
                                        return path
                            except:
                                pass
            except:
                pass

            # 5. Numaratör sistemindeki gibi tüm yöntemleri dene
            print(f"[DEBUG] 4. İleri düzey path yöntemleri...")
            try:
                # CATIA Application üzerinden bul
                if hasattr(self.__fikatia, 'catNesne'):
                    catia = self.__fikatia.catNesne
                    # Aktif dokümanların path'ini tara
                    for i in range(1, catia.Documents.Count + 1):
                        try:
                            doc = catia.Documents.Item(i)
                            if hasattr(doc, 'FullName'):
                                path = doc.FullName
                                if item.parcaNumarasi in path and path.endswith('.CATPart'):
                                    print(f"[DEBUG]   - Documents'de bulundu: {path}")
                                    return path
                        except:
                            pass
            except:
                pass

            # 6. Ana doküman klasörü + dosya adı tahmini
            if hasattr(self.__dokuman, 'klasoru'):
                dosya_adi = f"{item.parcaNumarasi}.CATPart"
                path = os.path.join(self.__dokuman.klasoru, dosya_adi)
                print(f"[DEBUG] 5. Ana klasör tahmini: {path}")
                return path

            # 7. Farklı dosya adı varyasyonlarını dene
            if hasattr(self.__dokuman, 'klasoru'):
                varyasyonlar = [
                    f"{item.parcaNumarasi}.CATPart",
                    f"{item.ismi}.CATPart",
                    f"{item.parcaNumarasi}.CATpart",
                    f"{item.parcaNumarasi}.catpart",
                    f"{item.parcaNumarasi}.part",
                    f"Part{item.parcaNumarasi}.CATPart",
                    f"{item.parcaNumarasi} (1).CATPart"
                ]
                for varyasyon in varyasyonlar:
                    path = os.path.join(self.__dokuman.klasoru, varyasyon)
                    if os.path.exists(path):
                        print(f"[DEBUG] 6. Dosya varyasyonu bulundu: {path}")
                        return path

        except Exception as e:
            print(f"[DEBUG] Part dosya yolu bulma hatası: {e}")

        print(f"[DEBUG] Part dosya yolu bulunamadı!")
        return None

    def _mevcut_producta_part_ekle(self, item, yogunluk):
        """
        Mevcut active product'a Part ekle ve işle
        Returns: (hacim, agirlik)
        """
        try:
            print(f"[DEBUG] Part mevcut product'a ekleniyor: {item.parcaNumarasi}")

            # Mevcut dokümanı al
            mevcut_dokuman = self.__dokuman

            # Mevcut dokümanın Product'ı olduğundan emin ol
            if not mevcut_dokuman:
                print(f"[DEBUG] Mevcut doküman bulunamadı")
                return 0.0, 0.0

            # Active dokümanın Product nesnesini al
            active_product = None
            try:
                if hasattr(mevcut_dokuman, 'catNesne'):
                    doc_com = mevcut_dokuman.catNesne
                    if hasattr(doc_com, 'Product'):
                        active_product = doc_com.Product
                    elif hasattr(doc_com, 'Products'):
                        active_product = doc_com  # Dokümanın kendisi Product olabilir
                elif hasattr(mevcut_dokuman, 'product'):
                    active_product = mevcut_dokuman.product.catNesne
                elif hasattr(mevcut_dokuman, 'productlar'):
                    if mevcut_dokuman.productlar.sayisi > 0:
                        active_product = mevcut_dokuman.productlar.item(0).catNesne

                if not active_product:
                    print(f"[DEBUG] Active product bulunamadı")
                    return 0.0, 0.0

                print(f"[DEBUG] ✓ Active product bulundu")

            except Exception as e:
                print(f"[DEBUG] Active product alma hatası: {e}")
                return 0.0, 0.0

            # Part'ı bu product'a ekle
            try:
                if hasattr(item, 'catNesne'):
                    part_com = item.catNesne

                    # Mevcut product'a Part eklemek için yöntemleri dene
                    # 1. Doğrudan Products.Add() ile dene
                    try:
                        # Eğer part_com bir Part ise doğrudan ekle
                        if hasattr(part_com, 'Name'):
                            active_product.Products.Add(part_com)
                            print(f"[DEBUG] ✓ Part doğrudan eklendi: {part_com.Name}")

                            # Eklenen Part'ın hacmini ve ağırlığını hesapla
                            hacim, agirlik = self._mevcut_product_part_hesapla(active_product, part_com, yogunluk)

                            return hacim, agirlik

                    except Exception as e:
                        print(f"[DEBUG] Doğrudan ekleme başarısız, DECProductToPart deneniyor: {e}")

                    # 2. DECProductToPart komutu ile dene
                    try:
                        dec_command = part_com.getitem("DECProductToPart")
                        if dec_command:
                            print(f"[DEBUG] DECProductToPart komutu çalıştırılıyor...")

                            # Komutu çalıştır
                            dec_command.Run()

                            # Sonucu al
                            result_part = dec_command.GetResult()
                            if result_part:
                                print(f"[DEBUG] DECProductToPart sonuçlandı")

                                # Sonucu active product'a ekle
                                active_product.Products.Add(result_part)
                                print(f"[DEBUG] ✓ DECProductToPart sonucu eklendi")

                                # Eklenen Part'ın hacmini ve ağırlığını hesapla
                                hacim, agirlik = self._mevcut_product_part_hesapla(active_product, result_part, yogunluk)

                                return hacim, agirlik
                            else:
                                print(f"[DEBUG] DECProductToPart sonucu yok")

                    except Exception as e:
                        print(f"[DEBUG] DECProductToPart komutu hatası: {e}")

                    # 3. Fallback: Mevcut yöntemlerle dene
                    print(f"[DEBUG] Fallback yöntem deneniyor...")
                    hacim, agirlik = self._part_ekleme_fallback(active_product, part_com, yogunluk)
                    if hacim > 0:
                        return hacim, agirlik

            except Exception as e:
                print(f"[DEBUG] _mevcut_producta_part_ekle genel hata: {e}")

        except Exception as e:
            print(f"[DEBUG] _mevcut_producta_part_ekle tam hata: {e}")

        return 0.0, 0.0

    def _gecici_product_part_hesapla(self, temp_doc, yogunluk):
        """
        Geçici product içindeki Part'ın hacimini ve ağırlığını hesapla
        Returns: (hacim, agirlik)
        """
        try:
            print(f"[DEBUG] Geçici product içindeki Part hesaplanıyor...")

            temp_product = temp_doc.Product

            # Product içindeki tek part'ı bul
            if hasattr(temp_product, 'Products') and temp_product.Products.Count > 0:
                part_product = temp_product.Products.Item(1)

                # Part olarak dönüştür
                if hasattr(part_product, 'Part'):
                    part_com = part_product.Part

                    # Hacmi hesapla
                    hacim = 0.0

                    try:
                        # SPAWorkbench ile tüm Body'lerin hacmini al
                        spa_workbench = temp_doc.GetWorkbench("SPAWorkbench")

                        if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                            bodies = part_com.Bodies
                            print(f"[DEBUG]   - {bodies.Count} Body bulundu")

                            for j in range(1, bodies.Count + 1):
                                try:
                                    body = bodies.Item(j)
                                    body_ref = part_com.CreateReferenceFromObject(body)
                                    measurable = spa_workbench.GetMeasurable(body_ref)
                                    body_vol = measurable.Volume
                                    hacim += body_vol
                                    print(f"[DEBUG]     - Body {j} ({body.Name}) = {body_vol:.6f} m³")
                                except Exception as e:
                                    print(f"[DEBUG]     - Body {j} hesaplama hatası: {e}")

                    except Exception as e:
                        print(f"[DEBUG] SPAWorkbench hatası: {e}")

                    # Fallback: Part'ın Volume özelliği
                    if hacim == 0 and hasattr(part_com, 'Volume'):
                        hacim = part_com.Volume
                        print(f"[DEBUG] Part Volume kullanıldı = {hacim:.6f} m³")

                    # Son deneme: GetTotalMass
                    if hacim > 0:
                        agirlik = hacim * yogunluk
                        print(f"[DEBUG]   ✓ Hacim = {hacim:.6f} m³, ağırlık = {agirlik:.3f} kg")
                        return hacim, agirlik
                    else:
                        # GetTotalMass dene
                        try:
                            agirlik = part_com.GetTotalMass()
                            if agirlik > 0:
                                hacim = agirlik / yogunluk
                                print(f"[DEBUG] GetTotalMass kullanıldı = {agirlik:.3f} kg")
                                return hacim, agirlik
                        except:
                            pass

        except Exception as e:
            print(f"[DEBUG] Geçici product hesaplama hatası: {e}")

        return 0.0, 0.0

    def _part_acip_isle(self, part_path, yogunluk):
        """
        Part dosyasını CATIA ile açıp gerçek hacim ve ağırlık hesapla
        Returns: (hacim, agirlik)
        """
        try:
            print(f"[DEBUG] Part CATIA ile açılıyor: {part_path}")

            # 1. FikomObject sistemi ile Part'ı CATIA'da aç
            from IFikomObject import IFikomObject
            from IDokuman import IDokuman
            from IPaylasilanlar import IPaylasilanlar
            from IPart import IPart

            # Mevcut CATIA bağlantısını kullan
            ana_program = self.__fikatia

            # Part dosyasını aç
            try:
                # Dokümanı aç
                part_dokuman = ana_program.dokumanlar.ac(part_path)
                print(f"[DEBUG] ✓ Part dokümanı açıldı: {part_dokuman.tamIsmi}")

                if part_dokuman:
                    # Part olarak dönüştür
                    part_obj = part_dokuman.asPartDokuman
                    if part_obj:
                        print(f"[DEBUG] ✓ Part objesi oluşturuldu")

                        # Part'ın hacmini ve ağırlığını hesapla
                        hacim = 0.0
                        agirlik = 0.0

                        try:
                            # Part'ın Bodies'ini al
                            part = part_obj.part
                            if hasattr(part, 'catNesne'):
                                part_com = part.catNesne

                                # SPAWorkbench ile hacmi hesapla
                                try:
                                    spa_workbench = part_com.GetWorkbench("SPAWorkbench")
                                    toplam_hacim = 0.0

                                    if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                                        bodies = part_com.Bodies
                                        print(f"[DEBUG]   - {bodies.Count} Body bulundu")

                                        for j in range(1, bodies.Count + 1):
                                            try:
                                                body = bodies.Item(j)
                                                body_ref = part_com.CreateReferenceFromObject(body)
                                                measurable = spa_workbench.GetMeasurable(body_ref)
                                                body_vol = measurable.Volume
                                                toplam_hacim += body_vol
                                                print(f"[DEBUG]     - Body {j} ({body.Name}) = {body_vol:.6f} m³")
                                            except Exception as e:
                                                print(f"[DEBUG]     - Body {j} hesaplama hatası: {e}")

                                        hacim = toplam_hacim
                                        if hacim > 0:
                                            agirlik = hacim * yogunluk
                                            print(f"[DEBUG]   ✓ Toplam hacim = {hacim:.6f} m³, ağırlık = {agirlik:.3f} kg")

                                except Exception as e:
                                    print(f"[DEBUG]   - SPAWorkbench hatası: {e}")

                                # Fallback: Part'ın Volume özelliği
                                if hacim == 0 and hasattr(part_com, 'Volume'):
                                    hacim = part_com.Volume
                                    agirlik = hacim * yogunluk
                                    print(f"[DEBUG]   - Part Volume kullanıldı = {hacim:.6f} m³")

                                # Son deneme: GetTotalMass
                                if agirlik == 0 and hasattr(part_com, 'GetTotalMass'):
                                    try:
                                        agirlik = part_com.GetTotalMass()
                                        if agirlik > 0:
                                            hacim = agirlik / yogunluk
                                            print(f"[DEBUG]   - GetTotalMass kullanıldı = {agirlik:.3f} kg")
                                    except:
                                        pass

                        except Exception as e:
                            print(f"[DEBUG]   - Part işlem hatası: {e}")

                        # Dokümanı kapat
                        try:
                            part_dokuman.kapat()
                            print(f"[DEBUG]   - Part dokümanı kapatıldı")
                        except:
                            pass

                        return hacim, agirlik

            except Exception as e:
                print(f"[DEBUG] Part açma hatası: {e}")

        except Exception as e:
            print(f"[DEBUG] _part_acip_isle genel hata: {e}")

        return 0.0, 0.0

    def _part_olculerini_acip_al(self, part_path):
        """
        Part dosyasını CATIA ile açıp gerçek ölçüleri al
        Returns: (min_x, min_y, min_z, max_x, max_y, max_z) or None
        """
        try:
            print(f"[DEBUG] Part ölçüleri için CATIA ile açılıyor: {part_path}")

            # FikomObject sistemi ile Part'ı aç
            from IFikomObject import IFikomObject
            from IDokuman import IDokuman
            from IPart import IPart

            ana_program = self.__fikatia

            try:
                # Dokümanı aç
                part_dokuman = ana_program.dokumanlar.ac(part_path)
                print(f"[DEBUG] ✓ Ölçü için Part dokümanı açıldı: {part_dokuman.tamIsmi}")

                if part_dokuman:
                    # Part olarak dönüştür
                    part_obj = part_dokuman.asPartDokuman
                    if part_obj:
                        # Mevcut Part ölçüsünü hesapla metodunu kullan
                        olculer = self._part_olculeri_hesapla(part_obj)
                        if olculer:
                            # UDF sonuçlarını BoundingBox'a çevir
                            x = olculer.get('x', 0) / 1000  # mm'den metreye
                            y = olculer.get('y', 0) / 1000
                            z = olculer.get('z', 0) / 1000

                            # Merkez etrafında BoundingBox oluştur
                            half_x = x / 2
                            half_y = y / 2
                            half_z = z / 2

                            min_x, min_y, min_z = -half_x, -half_y, -half_z
                            max_x, max_y, max_z = half_x, half_y, half_z

                            print(f"[DEBUG] ✓ Part ölçüleri: X={x:.1f}mm, Y={y:.1f}mm, Z={z:.1f}mm")
                            return (min_x, min_y, min_z, max_x, max_y, max_z)

                # Dokümanı kapat
                try:
                    part_dokuman.kapat()
                except:
                    pass

            except Exception as e:
                print(f"[DEBUG] Part ölçü alma hatası: {e}")

        except Exception as e:
            print(f"[DEBUG] _part_olculerini_acip_al genel hata: {e}")

        return None

    def _part_olculeri_hesapla(self, part_obj):
        """
        Part objesi için ölçüleri hesapla (mevcut _part_olculeri_hesapla mantığı)
        """
        try:
            from IYardimciSiniflar import SifirKonum, XYZ
            import os

            # UDF script dosyasının yolunu al
            current_dir = os.path.dirname(__file__)
            idialoglar = os.path.dirname(current_dir)
            fikatia_root = os.path.dirname(idialoglar)
            script_dosya = os.path.join(fikatia_root, "Prg", "FikoDosya", "FikoMfg0.FikoDll")

            if not os.path.exists(script_dosya):
                return None

            # Part'ı al
            part = part_obj.part
            part_com_obj = part.catNesne
            bodies = part_com_obj.Bodies

            if bodies.Count == 0:
                return None

            # HybridBody oluştur veya al
            try:
                fiko_body = part_com_obj.hybridBodies.item("FikoMantasyon")
                part_com_obj.InWorkObject = fiko_body
            except:
                fiko_body = part_com_obj.hybridBodies.add()
                fiko_body.name = "FikoMantasyon"

            # İlk body'yi al
            body = bodies.Item(1)

            # InstanceFactory ile UDF çağır
            factory = part_com_obj.GetCustomerFactory("InstanceFactory")
            factory.BeginInstanceFactory("Fiko0", script_dosya)
            factory.BeginInstantiate()
            factory.PutInputData("ParcaBody", body)
            instance = factory.Instantiate()
            factory.EndInstantiate()
            factory.EndInstanceFactory()

            # SPAWorkbench ile COG al
            spa_workbench = part_com_obj.GetWorkbench("SPAWorkbench")
            body_ref = part_com_obj.CreateReferenceFromObject(body)
            measurable = spa_workbench.GetMeasurable(body_ref)

            # COG al
            cog = (0.0, 0.0, 0.0)
            try:
                measurable.GetCOG(cog)
            except:
                cog = (0.0, 0.0, 0.0)

            # Origin ve axes ayarla
            instance.GetParameter("O.X").value = cog[0]
            instance.GetParameter("O.Y").value = cog[1]
            instance.GetParameter("O.Z").value = cog[2]
            instance.GetParameter("X.X").value = 1.0
            instance.GetParameter("X.Y").value = 0.0
            instance.GetParameter("X.Z").value = 0.0
            instance.GetParameter("Y.X").value = 0.0
            instance.GetParameter("Y.Y").value = 1.0
            instance.GetParameter("Y.Z").value = 0.0
            instance.GetParameter("Z.X").value = 0.0
            instance.GetParameter("Z.Y").value = 0.0
            instance.GetParameter("Z.Z").value = 1.0

            # Part'ı güncelle
            part_com_obj.Update()

            # Parametreleri oku
            xmin = instance.GetParameter("Xmin").value
            xmax = instance.GetParameter("Xmax").value
            ymin = instance.GetParameter("Ymin").value
            ymax = instance.GetParameter("Ymax").value
            zmin = instance.GetParameter("Zmin").value
            zmax = instance.GetParameter("Zmax").value

            # SifirKonum ile ölçüleri hesapla
            sifrkonum = SifirKonum(xmin, xmax, ymin, ymax, zmin, zmax)

            return {
                "x": round(sifrkonum.XOlcusu, 3),
                "y": round(sifrkonum.YOlcusu, 3),
                "z": round(sifrkonum.ZOlcusu, 3)
            }

        except Exception as e:
            print(f"[DEBUG] Part ölçü hesaplama hatası: {e}")
            return None

    def _fikoyt_klasoru_kontrol_et(self):
        """
        .fikoyt gizli klasörünü kontrol et ve oluştur
        """
        if not os.path.exists(self.FikoytKlasoru):
            try:
                os.makedirs(self.FikoytKlasoru)
                # Windows'ta gizli klasör yap
                import ctypes
                ctypes.windll.kernel32.SetFileAttributesW(self.FikoytKlasoru, 2)
            except Exception as e:
                QMessageBox.critical(self, "Hata",
                                   f".fikoyt klasörü oluşturulamadı: {e}")
                return False
        return True

    @pyqtSlot()
    def islem_yap(self):
        """
        Tüm işlemleri (WRL, Resim, Dokümantasyon) yapan ana method
        """
        try:
            # Başlangıç animasyonları
            self._animate_button_state(is_processing=True)
            self._show_loading(show=True, message="İşlem başlatılıyor...")
            self._update_progress(0, 5, "Başlatılıyor")
            self.app.processEvents()

            # 1. Klasör seçimi (checkbox'a göre)
            print("[DEBUG] Klasör seçimi yapılıyor...")
            self._update_progress(0.5, 5, "Klasör seçimi")

            # Checkbox kontrolü
            if hasattr(self.ui, 'checkFikoyt') and self.ui.checkFikoyt.isChecked():
                # .fikoyt klasörünü kullan
                kullanilacak_klasor = self.FikoytKlasoru
                if not self._fikoyt_klasoru_kontrol_et():
                    return
                print(f"[DEBUG] .fikoyt klasörü kullanılıyor: {kullanilacak_klasor}")
            else:
                # Windows temp klasörünü kullan
                kullanilacak_klasor = os.path.join(tempfile.gettempdir(), "FikoYT")
                if not os.path.exists(kullanilacak_klasor):
                    os.makedirs(kullanilacak_klasor)
                print(f"[DEBUG] Temp klasörü kullanılıyor: {kullanilacak_klasor}")

            # 2. WRL kaydet
            print("[DEBUG] WRL kaydediliyor...")
            self.ui.statusBar().showMessage("⏳ WRL kaydediliyor...")
            self._show_loading(show=True, message="WRL kaydediliyor...")
            self._update_progress(1, 5, "WRL Kaydet")
            self.app.processEvents()

            doc_com = self.__dokuman.catNesne
            wrl_dosya = os.path.join(kullanilacak_klasor, "model.wrl")

            if os.path.exists(wrl_dosya):
                try:
                    os.remove(wrl_dosya)
                except Exception:
                    pass

            doc_com.ExportData(wrl_dosya, "wrl")

            if not os.path.exists(wrl_dosya):
                raise RuntimeError(f"WRL dosyası oluşturulamadı")

            print(f"[DEBUG] ✓ WRL kaydedildi: {wrl_dosya}")
            self._update_progress(2, 5, "Resim Çek")
            self.app.processEvents()

            # 3. Resim çek
            print("[DEBUG] Resim çekiliyor...")
            self.ui.statusBar().showMessage("⏳ Resim çekiliyor...")
            self._show_loading(show=True, message="Resim çekiliyor...")
            self._animate_image_transition("", "loading")
            self.app.processEvents()

            gosterim = self.__dokuman.gosterim

            if gosterim is None:
                raise ValueError("Gosterim nesnesi alınamadı!")

            if hasattr(gosterim, 'catNesne'):
                gosterim_com = gosterim.catNesne
            else:
                gosterim_com = gosterim

            jpeg_dosya = os.path.join(kullanilacak_klasor, "screenshot.jpg")

            pencere = self.__dokuman.pencere

            # Ürün ağacını gizle (sadece Part için)
            try:
                if pencere and hasattr(pencere, 'catNesne'):
                    # Sadece Part dokümanlarında bu özellik çalışır
                    if hasattr(self.__dokuman, 'catNesne') and hasattr(self.__dokuman.catNesne, 'Part'):
                        pencere.catNesne.SpecificationPanelVisible = False
                        print(f"[DEBUG] Ürün ağacı gizlendi (Part dokümanı)")
                    else:
                        print(f"[DEBUG] Ürün ağacı gizleme atlandı (Product dokümanı)")
            except Exception as e:
                print(f"[DEBUG] Ürün ağacı gizleme hatası: {e} (Beklenen hata)")

            try:
                if not isinstance(gosterim, IGosterim3d):
                    gosterim = IGosterim3d(obj=gosterim_com, sahip=self.__dokuman)
                    gosterim.anaProgram = self.__fikatia

                gosterim.resimDosyaya(
                    jpeg_dosya,
                    Format=5,           # JPEG
                    ArkaPlan=[1, 1, 1], # Beyaz
                    Agac=False
                )
            finally:
                # Ürün ağacını geri göster
                try:
                    if pencere and hasattr(pencere, 'catNesne'):
                        pencere.catNesne.SpecificationPanelVisible = True
                except Exception:
                    pass

            if not os.path.exists(jpeg_dosya):
                raise RuntimeError(f"JPEG dosyası oluşturulamadı")

            print(f"[DEBUG] ✓ JPEG kaydedildi: {jpeg_dosya}")

            # 4. Resmi formda göster
            print("[DEBUG] Resim gösteriliyor...")
            self._show_loading(show=False)  # Loading animasyonu kapat
            self._animate_image_transition(jpeg_dosya, "success")
            self._resim_goster(jpeg_dosya)
            self._update_progress(3, 5, "Ağırlık Hesapla")
            self.app.processEvents()

            # 5. Ağırlık hesapla
            print("[DEBUG] Ağırlık hesaplanıyor...")
            self.ui.statusBar().showMessage("⏳ Ağırlık hesaplanıyor...")
            self._show_loading(show=True, message="Ağırlık hesaplanıyor...")
            self.app.processEvents()

            secilen_yogunluk = self._malzeme_yogunluk_al()
            agirlik = None
            hacim = None

            try:
                # 1. Direkt GetTotalMass() dene
                if hasattr(doc_com, 'GetTotalMass'):
                    try:
                        agirlik = doc_com.GetTotalMass()
                        print(f"[DEBUG] GetTotalMass() = {agirlik}")
                    except Exception as e:
                        print(f"[DEBUG] GetTotalMass() hatası: {e}")

                # 2. Product/Part üzerinden ağırlık hesapla
                if not agirlik:
                    try:
                        # Daha geniş Product tespiti - farklı CATIA versiyonları için
                        is_product = False
                        is_part = False

                        # Part kontrolü
                        if hasattr(doc_com, 'Part'):
                            is_part = True
                            print(f"[DEBUG] Part dokümanı tespit edildi")

                        # Product kontrolü - birden fazla yöntemle
                        elif hasattr(doc_com, 'Products'):
                            is_product = True
                            print(f"[DEBUG] Product dokümanı tespit edildi (Products)")
                        elif hasattr(doc_com, 'Product'):
                            is_product = True
                            print(f"[DEBUG] Product dokümanı tespit edildi (Product)")
                        elif hasattr(doc_com, 'Application'):
                            # CATIA Application üzerinden kontrol et
                            try:
                                active_doc = doc_com.Application.ActiveDocument
                                if hasattr(active_doc, 'Products') or hasattr(active_doc, 'Product'):
                                    is_product = True
                                    print(f"[DEBUG] Product dokümanı tespit edildi (Application)")
                                elif hasattr(active_doc, 'Part'):
                                    is_part = True
                                    print(f"[DEBUG] Part dokümanı tespit edildi (Application)")
                            except:
                                pass

                        # Doküman türüne göre ağırlık hesapla
                        if is_product:
                            agirlik = self._product_agirlik_hesapla(doc_com, secilen_yogunluk)
                        elif is_part:
                            agirlik = self._part_agirlik_hesapla(doc_com, secilen_yogunluk)
                        else:
                            print(f"[DEBUG] Bilinmeyen doküman türü - son deneme: mevcut metodlar")
                            # Son çare - deneme yanılma yöntemi
                            try:
                                # Product olarak dene
                                agirlik = self._product_agirlik_hesapla(doc_com, secilen_yogunluk)
                                if agirlik:
                                    print(f"[DEBUG] Product olarak başarılı")
                                else:
                                    # Part olarak dene
                                    agirlik = self._part_agirlik_hesapla(doc_com, secilen_yogunluk)
                                    if agirlik:
                                        print(f"[DEBUG] Part olarak başarılı")
                                    else:
                                        print(f"[DEBUG] Hiçbiri başarılı olmadı")
                            except Exception as e:
                                print(f"[DEBUG] Son deneme başarısız: {e}")

                    except Exception as e:
                        print(f"[DEBUG] Ağırlık hesaplama hatası: {e}")
                        import traceback
                        traceback.print_exc()

            except Exception as e:
                print(f"[ERROR] Ağırlık hesaplama hatası: {e}")
                import traceback
                traceback.print_exc()

            # 6. Ağırlık göster
            self._show_loading(show=False)  # Loading animasyonu kapat
            self._animate_data_update(self.ui.labelAgirlik, agirlik, "⚖️ ", " kg")
            self._update_progress(4, 5, "Ölçü Hesapla")
            self.app.processEvents()

            # 6.5. Ölçüleri hesapla ve göster
            print("[DEBUG] Ölçüler hesaplanıyor...")
            self._show_loading(show=True, message="Ölçüler hesaplanıyor...")
            olculer = self._olculer_hesapla_ve_goster()
            if olculer:
                olculer_text = f"📐 X:{olculer['x']:.3f} Y:{olculer['y']:.3f} Z:{olculer['z']:.3f}"
                self._animate_data_update(self.ui.labelOlculer, olculer_text, prefix="", suffix="")
            self._update_progress(5, 5, "Doküman Oluştur")
            self.app.processEvents()

            # 7. Dosya adı göster
            self._show_loading(show=False)  # Loading animasyonu kapat
            secilen_text = self.ui.comboMalzeme.currentText()
            malzeme_adi = secilen_text.split(" - ")[0] if " - " in secilen_text else secilen_text

            dokuman_adi = self.__dokuman.ismi
            self._animate_data_update(self.ui.labelDosyaIsmi, dokuman_adi, "📁 ", "")

            # 8. Dokümantasyon JSON oluştur
            print("[DEBUG] JSON oluşturuluyor...")
            self.ui.statusBar().showMessage("⏳ Dokümantasyon kaydediliyor...")
            self._show_loading(show=True, message="JSON oluşturuluyor...")
            self.app.processEvents()

            dokumantasyon = {
                "olusturma_tarihi": datetime.now().isoformat(),
                "dokuman_adi": dokuman_adi,
                "dokuman_tam_yolu": self.__dokuman.tamIsmi,
                "belge_turu": self.__dokuman.turu,
                "kaydedilmis": self.__dokuman.kaydedilmismi,
                "proje_klasoru": self.ProjeKlasoru,
                "kullanilan_klasor": kullanilacak_klasor,
                "fikoyt_modu": self.ui.checkFikoyt.isChecked() if hasattr(self.ui, 'checkFikoyt') else True,
                "agirlik_kg": agirlik,
                "agirlik_hesaplama": {
                    "malzeme": malzeme_adi,
                    "yogunluk_kg_m3": secilen_yogunluk,
                    "hacim_m3": hacim,
                    "birim": "kg",
                    "hesaplama_metodu": "Volume × Density" if hacim and secilen_yogunluk else "GetTotalMass()"
                },
                "olculer_mm": olculer if olculer else {"x": None, "y": None, "z": None},
                "islemler": {
                    "wrl_kayit": os.path.exists(wrl_dosya),
                    "resim_cikti": os.path.exists(jpeg_dosya),
                    "dokumantasyon": True
                }
            }

            json_dosya = os.path.join(kullanilacak_klasor, "dokumantasyon.json")
            with open(json_dosya, 'w', encoding='utf-8') as f:
                json.dump(dokumantasyon, f, indent=2, ensure_ascii=False)

            print(f"[DEBUG] ✓ JSON kaydedildi: {json_dosya}")

            # 9. Başarılı mesaj ve bitiş animasyonları
            self._show_loading(show=False)  # Tüm loading animasyonlarını kapat
            self._animate_button_state(is_processing=False)  # Butonu normale çevir

            # Kopyala butonunu aktif et
            if hasattr(self.ui, 'btnKopyala'):
                self.ui.btnKopyala.setEnabled(True)
                self.ui.btnKopyala.setStyleSheet("""
                    QPushButton {
                        background-color: #00ff88;
                        color: #0a0e27;
                        border: 2px solid #00ff88;
                        border-radius: 6px;
                        font-size: 9pt;
                        font-weight: bold;
                        padding: 2px;
                        outline: none;
                    }
                    QPushButton:hover {
                        background-color: #00ffaa;
                        border-color: #00ffaa;
                    }
                    QPushButton:pressed {
                        background-color: #00cc77;
                        border-color: #00cc77;
                    }
                    QPushButton:!disabled:focus {
                        border-color: #ffffff;
                    }
                """)

            self.ui.statusBar().showMessage("✅ Tüm işlemler tamamlandı!")
            self._animate_image_transition("", "success")
            self._update_progress(5, 5)  # İşlemler tamamlandı mesajı göster
            self.app.processEvents()

        except Exception as e:
            print(f"[ERROR] {str(e)}")
            import traceback
            traceback.print_exc()

            # Hata durumunda animasyonlar
            self._show_loading(show=False)
            self._animate_button_state(is_processing=False)  # Butonu normale çevir
            self._animate_image_transition("", "error")
            self.ui.statusBar().showMessage(f"❌ Hata: {str(e)}")
            QMessageBox.critical(self, "Hata", f"İşlem başarısız:\n{str(e)}")
            self.app.processEvents()

    def _resim_goster(self, jpeg_dosya):
        """
        JPEG resimini formda göster

        Args:
            jpeg_dosya: JPEG dosyasının tam yolu
        """
        try:
            if not os.path.exists(jpeg_dosya):
                print(f"[ERROR] Resim dosyası bulunamadı: {jpeg_dosya}")
                return

            pixmap = QPixmap(jpeg_dosya)
            if pixmap.isNull():
                print(f"[ERROR] Resim yüklenemedi")
                return

            # Resimi label'ın içine sığdır
            label_size = self.ui.labelResim.size()
            scaled_pixmap = pixmap.scaledToWidth(label_size.width() - 10, Qt.TransformationMode.SmoothTransformation)

            self.ui.labelResim.setPixmap(scaled_pixmap)
            print(f"[DEBUG] ✓ Resim gösterildi")

        except Exception as e:
            print(f"[ERROR] Resim gösterme hatası: {e}")

    def _agirlik_goster(self, agirlik):
        """
        Ağırlık değerini formda göster

        Args:
            agirlik: Ağırlık değeri (kg)
        """
        if agirlik:
            agirlik_text = f"⚖️ {agirlik:.2f} kg"
            self.ui.labelAgirlik.setText(agirlik_text)
            print(f"[DEBUG] Ağırlık gösterildi: {agirlik_text}")
        else:
            self.ui.labelAgirlik.setText("⚖️ Ağırlık: -")

    def _olculer_hesapla_ve_goster(self):
        """
        Part'ın veya Product'ın gerçek X, Y, Z ölçülerini hesapla
        Seçilen eksen varsa onu kullan, yoksa mevcut sistemin eksenlerini kullan
        Returns: dict with 'x', 'y', 'z' keys (mm), or None on error
        """
        try:
            from IYardimciSiniflar import SifirKonum, XYZ
            import os

            doc_com = self.__dokuman.catNesne

            # Doküman türünü kontrol et - daha kapsamlı yöntem
            is_product = False
            is_part = False

            # Part kontrolü
            if hasattr(doc_com, 'Part'):
                is_part = True
                print(f"[DEBUG] Ölçü için Part dokümanı tespit edildi")

            # Product kontrolü - birden fazla yöntemle
            elif hasattr(doc_com, 'Products'):
                is_product = True
                print(f"[DEBUG] Ölçü için Product dokümanı tespit edildi (Products)")
            elif hasattr(doc_com, 'Product'):
                is_product = True
                print(f"[DEBUG] Ölçü için Product dokümanı tespit edildi (Product)")
            elif hasattr(doc_com, 'Application'):
                # CATIA Application üzerinden kontrol et
                try:
                    active_doc = doc_com.Application.ActiveDocument
                    if hasattr(active_doc, 'Products') or hasattr(active_doc, 'Product'):
                        is_product = True
                        print(f"[DEBUG] Ölçü için Product dokümanı tespit edildi (Application)")
                    elif hasattr(active_doc, 'Part'):
                        is_part = True
                        print(f"[DEBUG] Ölçü için Part dokümanı tespit edildi (Application)")
                except:
                    pass

            # Doküman türüne göre ölçü hesapla
            if is_product:
                return self._product_olculeri_hesapla(doc_com)
            elif is_part:
                return self._part_olculeri_hesapla(doc_com)
            else:
                print(f"[DEBUG] Ölçü için bilinmeyen doküman türü - son deneme")
                try:
                    # Product olarak dene
                    result = self._product_olculeri_hesapla(doc_com)
                    if result:
                        return result
                    else:
                        # Part olarak dene
                        return self._part_olculeri_hesapla(doc_com)
                except:
                    self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                    return None

        except Exception as e:
            print(f"[ERROR] Ölçü hesaplama hatası: {e}")
            import traceback
            traceback.print_exc()
            self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
            return None

    def _part_olculeri_hesapla(self, doc_com):
        """
        Part dokümanı için ölçüleri hesapla (eski mantık)
        """
        try:
            from IYardimciSiniflar import SifirKonum, XYZ
            import os

            part_com_obj = doc_com.Part
            bodies = part_com_obj.Bodies

            if bodies.Count == 0:
                self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                return None

            # UDF script dosyasının yolunu al
            current_dir = os.path.dirname(__file__)
            idialoglar = os.path.dirname(current_dir)
            fikatia_root = os.path.dirname(idialoglar)
            script_dosya = os.path.join(fikatia_root, "Prg", "FikoDosya", "FikoMfg0.FikoDll")

            print(f"[DEBUG] UDF dosya: {script_dosya}, var: {os.path.exists(script_dosya)}")

            # HybridBody oluştur veya al
            try:
                fiko_body = part_com_obj.hybridBodies.item("FikoMantasyon")
                part_com_obj.InWorkObject = fiko_body
            except:
                fiko_body = part_com_obj.hybridBodies.add()
                fiko_body.name = "FikoMantasyon"

            # İlk body'yi al (COM object olarak)
            # Eğer body seçilmişse seçilen body'yi, yoksa ilk body'yi kullan
            if self.__aktifBody:
                body = self.__aktifBody.catNesne
                print(f"[DEBUG] Seçilen body kullanılıyor: {self.__aktifBody.ismi}")
            else:
                body = bodies.Item(1)
                print(f"[DEBUG] İlk body kullanılıyor: {body.Name}")

            # InstanceFactory ile UDF çağır (kutukSinirOlculeri gibi)
            factory = part_com_obj.GetCustomerFactory("InstanceFactory")
            factory.BeginInstanceFactory("Fiko0", script_dosya)
            factory.BeginInstantiate()

            # Body'nin COM nesnesini gönder (kutukSinirOlculeri gibi)
            factory.PutInputData("ParcaBody", body)

            instance = factory.Instantiate()
            factory.EndInstantiate()
            factory.EndInstanceFactory()

            # UDF'e merkez ve axes gönder
            # Seçilen eksen varsa onu kullan, yoksa mevcut sistemin eksenlerini/kullan
            # SPAWorkbench ile COG al
            spa_workbench = doc_com.GetWorkbench("SPAWorkbench")
            body_ref = part_com_obj.CreateReferenceFromObject(body)
            measurable = spa_workbench.GetMeasurable(body_ref)

            # COG al
            cog = (0.0, 0.0, 0.0)
            try:
                measurable.GetCOG(cog)
                print(f"[DEBUG] COG: {cog}")
            except Exception as e:
                print(f"[WARNING] COG hesaplanamadı ({e}), orijin noktası kullanılıyor")
                cog = (0.0, 0.0, 0.0)  # Orijin noktası kullan

            # Eğer seçilen eksen varsa onu kullan
            if self.__aktifEksen:
                print(f"[DEBUG] Seçilen eksen kullanılıyor: {self.__aktifEksen.ismi}")

                # Origin (Merkez - COG)
                instance.GetParameter("O.X").value = cog[0]
                instance.GetParameter("O.Y").value = cog[1]
                instance.GetParameter("O.Z").value = cog[2]

                # Seçilen eksenin X, Y, Z yönlerini al (artık IEksen nesnesi olduğu için doğrudan kullan)
                try:
                    x_dir = self.__aktifEksen.x
                    y_dir = self.__aktifEksen.y
                    z_dir = self.__aktifEksen.z
                    print(f"[DEBUG] Eksen vektörleri alındı: X={x_dir.X}, Y={x_dir.Y}, Z={x_dir.Z}")
                except Exception as e:
                    print(f"[ERROR] Eksen vektörleri alınırken hata: {e}")
                    # Hata durumunda global axes kullan
                    instance.GetParameter("O.X").value = cog[0]
                    instance.GetParameter("O.Y").value = cog[1]
                    instance.GetParameter("O.Z").value = cog[2]
                    instance.GetParameter("X.X").value = 1.0
                    instance.GetParameter("X.Y").value = 0.0
                    instance.GetParameter("X.Z").value = 0.0
                    instance.GetParameter("Y.X").value = 0.0
                    instance.GetParameter("Y.Y").value = 1.0
                    instance.GetParameter("Y.Z").value = 0.0
                    instance.GetParameter("Z.X").value = 0.0
                    instance.GetParameter("Z.Y").value = 0.0
                    instance.GetParameter("Z.Z").value = 1.0
                    print(f"[DEBUG] Hata nedeniyle global axes kullanılıyor")

                # X axis
                instance.GetParameter("X.X").value = x_dir.X
                instance.GetParameter("X.Y").value = x_dir.Y
                instance.GetParameter("X.Z").value = x_dir.Z

                # Y axis
                instance.GetParameter("Y.X").value = y_dir.X
                instance.GetParameter("Y.Y").value = y_dir.Y
                instance.GetParameter("Y.Z").value = y_dir.Z

                # Z axis
                instance.GetParameter("Z.X").value = z_dir.X
                instance.GetParameter("Z.Y").value = z_dir.Y
                instance.GetParameter("Z.Z").value = z_dir.Z

                print(f"[DEBUG] UDF parametreleri ayarlandı (seçilen eksen kullanıldı)")
            else:
                # Eksen seçilmemişse, mevcut sistemin eksenlerini kullan (eski mantık)
                print(f"[DEBUG] Eksen seçilmemiş, mevcut sistem eksenleri kullanılıyor")

                # Part'ın eksenlerini al (IPart wrapper'ı kullan)
                from IPart import IPart
                part_wrapper = IPart(part_com_obj)
                eksenler = part_wrapper.eksenler

                # Son ekseni bul (son eklenen eksen)
                if eksenler.sayisi > 0:
                    son_eksen = eksenler.item(eksenler.sayisi-1)
                    print(f"[DEBUG] Son eksen bulundu: {son_eksen.ismi}")

                    # Origin (Merkez - COG)
                    instance.GetParameter("O.X").value = cog[0]
                    instance.GetParameter("O.Y").value = cog[1]
                    instance.GetParameter("O.Z").value = cog[2]

                    # Son eksenin X, Y, Z yönlerini al
                    x_dir = son_eksen.x
                    y_dir = son_eksen.y
                    z_dir = son_eksen.z

                    # X axis
                    instance.GetParameter("X.X").value = x_dir.X
                    instance.GetParameter("X.Y").value = x_dir.Y
                    instance.GetParameter("X.Z").value = x_dir.Z

                    # Y axis
                    instance.GetParameter("Y.X").value = y_dir.X
                    instance.GetParameter("Y.Y").value = y_dir.Y
                    instance.GetParameter("Y.Z").value = y_dir.Z

                    # Z axis
                    instance.GetParameter("Z.X").value = z_dir.X
                    instance.GetParameter("Z.Y").value = z_dir.Y
                    instance.GetParameter("Z.Z").value = z_dir.Z

                    print(f"[DEBUG] UDF parametreleri ayarlandı (son eksen kullanıldı)")
                else:
                    # Eksen yoksa global axes kullan
                    print(f"[DEBUG] Eksen yok, global axes kullanılıyor")
                    instance.GetParameter("O.X").value = cog[0]
                    instance.GetParameter("O.Y").value = cog[1]
                    instance.GetParameter("O.Z").value = cog[2]

                    instance.GetParameter("X.X").value = 1.0
                    instance.GetParameter("X.Y").value = 0.0
                    instance.GetParameter("X.Z").value = 0.0

                    instance.GetParameter("Y.X").value = 0.0
                    instance.GetParameter("Y.Y").value = 1.0
                    instance.GetParameter("Y.Z").value = 0.0

                    instance.GetParameter("Z.X").value = 0.0
                    instance.GetParameter("Z.Y").value = 0.0
                    instance.GetParameter("Z.Z").value = 1.0

            # Part'ı güncelle (UDF parametreleri hesaplansın)
            print(f"[DEBUG] Part güncelleniyor...")
            part_com_obj.Update()

            # Parametreleri oku
            xmin = instance.GetParameter("Xmin").value
            xmax = instance.GetParameter("Xmax").value
            ymin = instance.GetParameter("Ymin").value
            ymax = instance.GetParameter("Ymax").value
            zmin = instance.GetParameter("Zmin").value
            zmax = instance.GetParameter("Zmax").value

            print(f"[DEBUG] UDF Params: Xmin={xmin}, Xmax={xmax}, Ymin={ymin}, Ymax={ymax}, Zmin={zmin}, Zmax={zmax}")

            # SifirKonum ile ölçüleri hesapla
            sifrkonum = SifirKonum(xmin, xmax, ymin, ymax, zmin, zmax)

            x_olcu = sifrkonum.XOlcusu
            y_olcu = sifrkonum.YOlcusu
            z_olcu = sifrkonum.ZOlcusu

            print(f"[DEBUG] Ölçüler: X={x_olcu:.3f}mm, Y={y_olcu:.3f}mm, Z={z_olcu:.3f}mm")

            # Hangi eksen kullanıldığını göster
            eksen_info = f" (Seçilen Eksen)" if self.__aktifEksen else f" (Sistem Ekseni)"
            olculer_text = f"📐 X:{x_olcu:.3f} Y:{y_olcu:.3f} Z:{z_olcu:.3f}{eksen_info}"
            self.ui.labelOlculer.setText(olculer_text)

            # Ölçüleri return et (JSON'a eklemek için)
            return {
                "x": round(x_olcu, 3),
                "y": round(y_olcu, 3),
                "z": round(z_olcu, 3),
                "kullanilan_eksen": self.__aktifEksen.ismi if self.__aktifEksen else "sistem_ekseni"
            }

        except Exception as e:
            print(f"[ERROR] Part ölçü hesaplama hatası: {e}")
            self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
            return None

    def _product_olculeri_hesapla(self, doc_com):
        """
        Product dokümanı için içindeki tüm Part'ların toplam ölçülerini hesapla
        """
        try:
            # Önce IProduct wrapper'ını kullanmayı dene
            try:
                # IProduct sınıfını import et
                sys.path.insert(0, _project_root)
                from IProduct import IProduct

                # Doğru Product nesnesini bul (ağırlık ile aynı mantık)
                product_com = None

                # 1. doc_com.Product kontrolü
                if hasattr(doc_com, 'Product'):
                    product_com = doc_com.Product
                    print(f"[DEBUG] Ölçü için doc_com.Product bulundu")

                # 2. doc_com'un kendisi Product mi kontrolü
                elif hasattr(doc_com, 'Products'):
                    product_com = doc_com
                    print(f"[DEBUG] Ölçü için doc_com kendisi Product")

                # 3. Application üzerinden dene
                elif hasattr(doc_com, 'Application'):
                    try:
                        active_doc = doc_com.Application.ActiveDocument
                        if hasattr(active_doc, 'Product'):
                            product_com = active_doc.Product
                        elif hasattr(active_doc, 'Products'):
                            product_com = active_doc
                        print(f"[DEBUG] Ölçü için Application üzerinden Product bulundu")
                    except:
                        pass

                if not product_com:
                    print(f"[DEBUG] Ölçü için Product nesnesi bulunamadı")
                    self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                    return None

                # IProduct wrapper'ı oluştur
                product_wrapper = IProduct(obj=product_com, sahip=None)
                print(f"[DEBUG] Ölçü için IProduct wrapper oluşturuldu")

                # Product'ın içindeki ürünleri IProductlar ile al
                products = product_wrapper.productlar
                product_count = products.sayisi
                print(f"[DEBUG] IProductlar ile {product_count} ürün bulundu (ölçü)")

                if product_count == 0:
                    print(f"[DEBUG] Ölçü için Product içinde alt ürün bulunamadı")
                    self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                    return None

                min_x, min_y, min_z = float('inf'), float('inf'), float('inf')
                max_x, max_y, max_z = float('-inf'), float('-inf'), float('-inf')
                part_sayisi = 0

                print(f"[DEBUG] Product içindeki Part'ların ölçüleri IProduct ile hesaplanıyor...")

                # Tüm ürünleri tara
                for i in range(product_count):
                    try:
                        item = products.item(i)
                        print(f"[DEBUG] Ölçüleniyor: Product {i+1}/{product_count}")

                        # Eğer bu bir Part ise
                        if item.partMi:
                            part_sayisi += 1
                            print(f"[DEBUG]   ✓ Part ölçüleniyor: {item.parcaNumarasi} - {item.ismi}")

                            # Part'ın hacimsel sınırlarını hesapla
                            try:
                                # ReferansProduct üzerinden Part belgesine eriş
                                part_doc = None
                                ref_product = item.referansProduct

                                if hasattr(ref_product, 'dokuman'):
                                    part_doc = ref_product.dokuman
                                elif hasattr(ref_product, 'catNesne'):
                                    cat_obj = ref_product.catNesne
                                    part_obj = cat_obj.GetTechnologicalObject("Part")
                                    if part_obj:
                                        part_doc = type('PartDoc', (), {'catNesne': part_obj})()

                                if part_doc:
                                    # Part'ın BoundingBox'unu hesapla
                                    try:
                                        # Part'ın dosya yolunu bul ve aç
                                        part_path = self._part_dosya_yolu_bul(item)
                                        if part_path and os.path.exists(part_path):
                                            print(f"[DEBUG]   - Part ölçüsü için dosya: {part_path}")
                                            # Part'ı ayrı olarak işle
                                            bbox = self._part_olculerini_acip_al(part_path)
                                            if bbox:
                                                min_x = min(min_x, bbox[0])
                                                min_y = min(min_y, bbox[1])
                                                min_z = min(min_z, bbox[2])
                                                max_x = max(max_x, bbox[3])
                                                max_y = max(max_y, bbox[4])
                                                max_z = max(max_z, bbox[5])
                                                print(f"[DEBUG]   ✓ Part bbox: {bbox}")
                                            else:
                                                print(f"[DEBUG]   - Part bbox alınamadı, eski yöntem deneniyor")
                                                # Fallback: Eski yöntemle dene
                                                bbox = self._part_bounding_box_hesapla(part_doc)
                                                if bbox:
                                                    min_x = min(min_x, bbox[0])
                                                    min_y = min(min_y, bbox[1])
                                                    min_z = min(min_z, bbox[2])
                                                    max_x = max(max_x, bbox[3])
                                                    max_y = max(max_y, bbox[4])
                                                    max_z = max(max_z, bbox[5])
                                        else:
                                            print(f"[DEBUG]   - Part dosya yolu bulunamadı: {part_path}")
                                            # Fallback: Eski yöntemle dene
                                            bbox = self._part_bounding_box_hesapla(part_doc)
                                            if bbox:
                                                min_x = min(min_x, bbox[0])
                                                min_y = min(min_y, bbox[1])
                                                min_z = min(min_z, bbox[2])
                                                max_x = max(max_x, bbox[3])
                                                max_y = max(max_y, bbox[4])
                                                max_z = max(max_z, bbox[5])
                                    except Exception as e:
                                        print(f"[DEBUG]   - Part ölçü hatası: {e}")
                                        # Fallback: Eski yöntemle dene
                                        bbox = self._part_bounding_box_hesapla(part_doc)
                                        if bbox:
                                            min_x = min(min_x, bbox[0])
                                            min_y = min(min_y, bbox[1])
                                            min_z = min(min_z, bbox[2])
                                            max_x = max(max_x, bbox[3])
                                            max_y = max(max_y, bbox[4])
                                            max_z = max(max_z, bbox[5])

                            except Exception as e:
                                print(f"[DEBUG]   - Part ölçü hatası: {e}")

                        else:
                            print(f"[DEBUG]   - Bu bir Product: {item.parcaNumarasi} - {item.ismi}")

                    except Exception as e:
                        print(f"[DEBUG] Product {i+1} ölçülenemedi: {e}")

                # Sonuçları kontrol et
                if min_x == float('inf') or max_x == float('-inf'):
                    print(f"[DEBUG] Product ölçüleri IProduct ile alınamadı, fallback deneniyor")
                    self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                    return None

                # Ölçüleri hesapla
                x_olcu = (max_x - min_x) * 1000  # metreden mm'ye çevir
                y_olcu = (max_y - min_y) * 1000
                z_olcu = (max_z - min_z) * 1000

                print(f"[DEBUG] Product ölçüleri: X={x_olcu:.3f}mm, Y={y_olcu:.3f}mm, Z={z_olcu:.3f}mm ({part_sayisi} Part)")

                olculer_text = f"📐 X:{x_olcu:.3f} Y:{y_olcu:.3f} Z:{z_olcu:.3f} (Toplam Product)"
                self.ui.labelOlculer.setText(olculer_text)

                return {
                    "x": round(x_olcu, 3),
                    "y": round(y_olcu, 3),
                    "z": round(z_olcu, 3),
                    "kullanilan_eksen": "product_toplami"
                }

            except ImportError as e:
                print(f"[DEBUG] IProduct import hatası (ölçü): {e}")
                self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                return None

        except Exception as e:
            print(f"[ERROR] Product ölçü hesaplama hatası: {e}")
            import traceback
            traceback.print_exc()
            self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
            return None

            # Product içindeki tüm Part'ları tara
            for i in range(1, product_count + 1):
                try:
                    product = products.Item(i)
                    print(f"[DEBUG] Ölçüleniyor: Product {i}/{product_count}")

                    # Her bir Product'ın farklı özelliklerini kontrol et
                    ref_name = "Unknown"
                    try:
                        if hasattr(product, 'Name'):
                            ref_name = product.Name
                        elif hasattr(product, 'Reference') and product.Reference:
                            ref_name = product.Reference.Name
                        elif hasattr(product, 'PartNumber'):
                            ref_name = product.PartNumber
                        print(f"[DEBUG]   Product adı: {ref_name}")
                    except:
                        print(f"[DEBUG]   Product adı alınamadı")

                    # Farklı yöntemlerle Part'ı bulmaya çalış (ağırlık hesabıyla aynı mantık)
                    part_doc = None

                    # 1. Direkt Part özelliği
                    if hasattr(product, 'Part'):
                        try:
                            part_doc = product.Part
                        except:
                            pass

                    # 2. Reference üzerinden
                    if not part_doc and hasattr(product, 'Reference') and product.Reference:
                        try:
                            part_doc = product.Reference.Part
                        except:
                            pass

                    # 3. Product'ın kendisi bir Part olabilir
                    if not part_doc:
                        try:
                            if hasattr(product, 'Bodies'):
                                part_doc = product
                        except:
                            pass

                    # 4. Definition üzerinden
                    if not part_doc and hasattr(product, 'Definition'):
                        try:
                            if hasattr(product.Definition, 'Part'):
                                part_doc = product.Definition.Part
                        except:
                            pass

                    # 5. Product'ın tüm özelliklerini tara (debug için)
                    if not part_doc:
                        try:
                            # Özel özellikleri kontrol et
                            special_attrs = ['Part', 'Bodies', 'Shape', 'ReferenceObject', 'Master', 'Instance']
                            for attr in special_attrs:
                                if hasattr(product, attr):
                                    try:
                                        val = getattr(product, attr)
                                        # Eğer Bodies varsa, Product'ın kendisi Part'tır
                                        if attr == 'Bodies' and hasattr(val, 'Count') and val.Count > 0:
                                            part_doc = product
                                    except:
                                        pass
                        except:
                            pass

                    # 6. Son deneme - Product'ı direkt olarak Part olarak kullan
                    if not part_doc:
                        try:
                            if hasattr(product, 'Volume') or hasattr(product, 'Bodies'):
                                part_doc = product
                            elif hasattr(product, 'GetTechnologicalObject'):
                                part_obj = product.GetTechnologicalObject("Part")
                                if part_obj:
                                    part_doc = part_obj
                        except:
                            pass

                    if part_doc and hasattr(part_doc, 'Bodies') and part_doc.Bodies.Count > 0:
                        part_sayisi += 1
                        print(f"[DEBUG]   ✓ Part ölçüleniyor: {ref_name}")

                        # Bu Part içindeki tüm Body'lerin bounding box'ını hesapla
                        for j in range(1, part_doc.Bodies.Count + 1):
                            try:
                                body = part_doc.Bodies.Item(j)
                                body_ref = part_doc.CreateReferenceFromObject(body)
                                measurable = spa_workbench.GetMeasurable(body_ref)

                                # Body'nin bounding box'ını al
                                try:
                                    # CATIA V5'te GetBoundingBox metodu var mı kontrol et
                                    if hasattr(measurable, 'GetBoundingBox'):
                                        bbox = measurable.GetBoundingBox()
                                        # bbox = (min_x, min_y, min_z, max_x, max_y, max_z) formatında
                                        if bbox and len(bbox) >= 6:
                                            min_x = min(min_x, bbox[0])
                                            min_y = min(min_y, bbox[1])
                                            min_z = min(min_z, bbox[2])
                                            max_x = max(max_x, bbox[3])
                                            max_y = max(max_y, bbox[4])
                                            max_z = max(max_z, bbox[5])
                                            print(f"[DEBUG]     - Body {j} bbox alındı")
                                        else:
                                            # BoundingBox alınamazsa COG kullan
                                            raise Exception("Empty bbox")
                                    else:
                                        raise Exception("No GetBoundingBox")
                                except:
                                    # BoundingBox alınamazsa COG ve min/max pointleri kullan
                                    cog = (0.0, 0.0, 0.0)
                                    try:
                                        measurable.GetCOG(cog)
                                        # COG etrafında küçük bir bounding box oluştur
                                        tolerance = 0.01  # 10mm tolerance
                                        min_x = min(min_x, cog[0] - tolerance)
                                        min_y = min(min_y, cog[1] - tolerance)
                                        min_z = min(min_z, cog[2] - tolerance)
                                        max_x = max(max_x, cog[0] + tolerance)
                                        max_y = max(max_y, cog[1] + tolerance)
                                        max_z = max(max_z, cog[2] + tolerance)
                                        print(f"[DEBUG]     - Body {j} COG ile yaklaşık bbox")
                                    except:
                                        pass

                            except Exception as e:
                                print(f"[DEBUG]     - Body {j} ölçü hatası: {e}")

                    elif part_doc:
                        print(f"[DEBUG]   - Part {ref_name} içinde Body bulunamadı")
                    else:
                        print(f"[DEBUG]   - Part bulunamadı: {ref_name}")

                except Exception as e:
                    print(f"[DEBUG] Product {i} ölçülenemedi: {e}")

            # Sonuçları kontrol et
            if min_x == float('inf') or max_x == float('-inf'):
                print(f"[DEBUG] Product ölçüleri alınamadı")
                self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
                return None

            # Ölçüleri hesapla
            x_olcu = (max_x - min_x) * 1000  # metreden mm'ye çevir
            y_olcu = (max_y - min_y) * 1000
            z_olcu = (max_z - min_z) * 1000

            print(f"[DEBUG] Product ölçüleri: X={x_olcu:.3f}mm, Y={y_olcu:.3f}mm, Z={z_olcu:.3f}mm ({part_sayisi} Part)")

            olculer_text = f"📐 X:{x_olcu:.3f} Y:{y_olcu:.3f} Z:{z_olcu:.3f} (Toplam Product)"
            self.ui.labelOlculer.setText(olculer_text)

            return {
                "x": round(x_olcu, 3),
                "y": round(y_olcu, 3),
                "z": round(z_olcu, 3),
                "kullanilan_eksen": "product_toplami"
            }

        except Exception as e:
            print(f"[ERROR] Product ölçü hesaplama hatası: {e}")
            import traceback
            traceback.print_exc()
            self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
            return None

        except Exception as e:
            print(f"[ERROR] Ölçü hesaplama hatası: {e}")
            import traceback
            traceback.print_exc()
            self.ui.labelOlculer.setText("📐 X:- Y:- Z:-")
            return None

    def _mevcut_product_part_hesapla(self, active_product, result_part, yogunluk):
        """
        Mevcut Product'a eklenen Part'ın hacimini ve ağırlığını hesaplar
        Returns: (hacim, agirlik)
        """
        try:
            print(f"[DEBUG] Eklenen Part hesaplanıyor...")

            # Eklenen Part'ın COM nesnesini al
            part_com = None
            if hasattr(result_part, 'catNesne'):
                part_com = result_part.catNesne
            elif hasattr(result_part, 'Part'):
                part_com = result_part.Part
            elif hasattr(active_product, 'Products') and active_product.Products.Count > 0:
                # Son eklenen Product'ı al
                son_product = active_product.Products.Item(active_product.Products.Count)
                if hasattr(son_product, 'Part'):
                    part_com = son_product.Part

            if not part_com:
                print(f"[DEBUG] Eklenen Part'ın COM nesnesi bulunamadı")
                return 0.0, 0.0

            print(f"[DEBUG] ✓ Part COM nesnesi bulundu")

            # Hacmi hesapla
            hacim = 0.0

            try:
                # Dokümanı geçici olarak aç
                doc = part_com.Parent
                if doc:
                    # SPAWorkbench ile tüm Body'lerin hacmini al
                    spa_workbench = doc.GetWorkbench("SPAWorkbench")

                    if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                        bodies = part_com.Bodies
                        print(f"[DEBUG]   - {bodies.Count} Body bulundu")

                        for j in range(1, bodies.Count + 1):
                            try:
                                body = bodies.Item(j)
                                body_ref = part_com.CreateReferenceFromObject(body)
                                measurable = spa_workbench.GetMeasurable(body_ref)
                                body_vol = measurable.Volume
                                hacim += body_vol
                                print(f"[DEBUG]     - Body {j} ({body.Name}) = {body_vol:.6f} m³")
                            except Exception as e:
                                print(f"[DEBUG]     - Body {j} hesaplama hatası: {e}")

            except Exception as e:
                print(f"[DEBUG] SPAWorkbench hatası: {e}")

                # Fallback: Part'ın Volume özelliği
                if hacim == 0 and hasattr(part_com, 'Volume'):
                    hacim = part_com.Volume
                    print(f"[DEBUG] Part Volume kullanıldı = {hacim:.6f} m³")

            # Son deneme: GetTotalMass
            if hacim > 0:
                agirlik = hacim * yogunluk
                print(f"[DEBUG]   ✓ Hacim = {hacim:.6f} m³, ağırlık = {agirlik:.3f} kg")
                return hacim, agirlik
            else:
                # GetTotalMass dene
                try:
                    agirlik = part_com.GetTotalMass()
                    if agirlik > 0:
                        hacim = agirlik / yogunluk
                        print(f"[DEBUG] GetTotalMass kullanıldı = {agirlik:.3f} kg")
                        return hacim, agirlik
                except:
                    pass

            print(f"[DEBUG]   ✗ Hacim ve ağırlık hesaplanamadı")
            return 0.0, 0.0

        except Exception as e:
            print(f"[DEBUG] _mevcut_product_part_hesapla hatası: {e}")
            return 0.0, 0.0

    def _part_ekleme_fallback(self, active_product, part_com, yogunluk):
        """
        Part ekleme işlemi başarısız olduğunda kullanılan fallback yöntemi
        Returns: (hacim, agirlik)
        """
        try:
            print(f"[DEBUG] Part ekleme fallback deneniyor...")

            # Mevcut Product'ta doğrudan hesaplama dene
            if part_com:
                # Doğrudan Part'ın özelliklerini kullan
                try:
                    # Volume özelliğini kontrol et
                    if hasattr(part_com, 'Volume'):
                        hacim = part_com.Volume
                        if hacim > 0:
                            agirlik = hacim * yogunluk
                            print(f"[DEBUG] Fallback Volume kullanıldı = {hacim:.6f} m³, ağırlık = {agirlik:.3f} kg")
                            return hacim, agirlik

                    # GetTotalMass dene
                    if hasattr(part_com, 'GetTotalMass'):
                        agirlik = part_com.GetTotalMass()
                        if agirlik > 0:
                            hacim = agirlik / yogunluk
                            print(f"[DEBUG] Fallback GetTotalMass kullanıldı = {agirlik:.3f} kg")
                            return hacim, agirlik

                    # Body'leri dene
                    if hasattr(part_com, 'Bodies') and part_com.Bodies.Count > 0:
                        doc = part_com.Parent
                        if doc:
                            spa_workbench = doc.GetWorkbench("SPAWorkbench")
                            hacim = 0.0

                            for j in range(1, part_com.Bodies.Count + 1):
                                try:
                                    body = part_com.Bodies.Item(j)
                                    body_ref = part_com.CreateReferenceFromObject(body)
                                    measurable = spa_workbench.GetMeasurable(body_ref)
                                    body_vol = measurable.Volume
                                    hacim += body_vol
                                except:
                                    pass

                            if hacim > 0:
                                agirlik = hacim * yogunluk
                                print(f"[DEBUG] Fallback Body hacmi = {hacim:.6f} m³, ağırlık = {agirlik:.3f} kg")
                                return hacim, agirlik

                except Exception as e:
                    print(f"[DEBUG] Fallback Part hesaplama hatası: {e}")

            print(f"[DEBUG] Fallback yöntemi de başarısız")
            return 0.0, 0.0

        except Exception as e:
            print(f"[DEBUG] _part_ekleme_fallback hatası: {e}")
            return 0.0, 0.0

    def closeEvent(self, event):
        """Pencere kapatılırken çağrılır"""
        event.accept()

    def __str__(self):
        return f"IFikoCikariciDialog(dokuman={self.__dokuman.ismi})"


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle("fusion")

    cizgiYumusatici = IFikoCikariciDialog(Catia=Dispatch("Catia.Application"))
    cizgiYumusatici.show()

    sys.exit(app.exec())
