import sys
import os
import json
import inspect
import socket
import tempfile
from pathlib import Path
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
import base64

from PyQt6.QtWidgets import (QApplication, QMainWindow, QMessageBox,
                             QTextEdit, QVBoxLayout, QWidget, QPushButton,
                             QLabel, QHBoxLayout, QSpinBox)
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot, QTimer
from PyQt6.QtGui import QMovie, QTextCursor
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 IDokuman import IDokuman
from IDialoglar.IDialogCevirici.threadManager import Async


class CeviriciRequestHandler(BaseHTTPRequestHandler):
    """
    HTTP Request Handler - WRL Dönüştürme İsteklerini İşler

    POST /convert - Dosya dönüştürme isteği
    GET /status - Server durumu
    GET /health - Health check
    """

    def log_message(self, format, *args):
        """Log mesajlarını ana dialog'a gönder"""
        message = f"{self.address_string()} - {format % args}"
        if hasattr(self.server, 'dialog_window'):
            self.server.dialog_window.log_signal.emit(message)

    def do_GET(self):
        """GET istekleri - Durum kontrolü"""
        if self.path == '/status':
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()

            status = {
                'status': 'running',
                'server': 'IDialogCevirici',
                'version': '1.0',
                'timestamp': datetime.now().isoformat(),
                'catia_connected': hasattr(self.server, 'catia_app') and self.server.catia_app is not None
            }
            self.wfile.write(json.dumps(status, ensure_ascii=False).encode('utf-8'))

        elif self.path == '/health':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write(b'OK')

        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'Not Found')

    def do_POST(self):
        """POST istekleri - Dosya dönüştürme"""
        if self.path == '/convert':
            try:
                # İstek gövdesini oku
                content_length = int(self.headers['Content-Length'])
                post_data = self.rfile.read(content_length)
                request_data = json.loads(post_data.decode('utf-8'))

                # Gerekli parametreleri al
                source_file = request_data.get('source_file')
                output_dir = request_data.get('output_dir', tempfile.gettempdir())
                output_name = request_data.get('output_name', 'converted')

                if not source_file:
                    self.send_error(400, "source_file parametresi gerekli")
                    return

                if not os.path.exists(source_file):
                    self.send_error(404, f"Kaynak dosya bulunamadı: {source_file}")
                    return

                # CATIA ile dosyayı aç ve WRL'e dönüştür
                result = self.server.convert_to_wrl(source_file, output_dir, output_name)

            except Exception as e:
                self.send_error(500, f"Dönüştürme hatası: {str(e)}")
                return

            # Başarılı yanıt
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps(result, ensure_ascii=False).encode('utf-8'))

        elif self.path == '/convert_batch':
            # Batch mode ile dönüştürme (CATIA'yı bağımsız başlatır)
            try:
                # İstek gövdesini oku
                content_length = int(self.headers['Content-Length'])
                post_data = self.rfile.read(content_length)
                request_data = json.loads(post_data.decode('utf-8'))

                # Gerekli parametreleri al
                source_file = request_data.get('source_file')
                output_dir = request_data.get('output_dir', tempfile.gettempdir())
                output_name = request_data.get('output_name', 'converted')

                if not source_file:
                    self.send_error(400, "source_file parametresi gerekli")
                    return

                if not os.path.exists(source_file):
                    self.send_error(404, f"Kaynak dosya bulunamadı: {source_file}")
                    return

                # Batch mode ile dönüştür
                result = self.server.convert_to_wrl_batch(source_file, output_dir, output_name)

                # Başarılı yanıt
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()

                response = {
                    'success': True,
                    'source_file': source_file,
                    'output_file': result['output_file'],
                    'timestamp': datetime.now().isoformat()
                }

                self.wfile.write(json.dumps(response, ensure_ascii=False).encode('utf-8'))

            except Exception as e:
                self.send_error(500, f"Dönüştürme hatası: {str(e)}")
                if hasattr(self.server, 'dialog_window'):
                    self.server.dialog_window.log_signal.emit(f"HATA: {str(e)}")

        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'Not Found')


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Thread'li HTTP Server - Her istek ayrı thread'de işlenir"""
    daemon_threads = True

    def __init__(self, server_address, RequestHandlerClass, catia_app=None, dialog_window=None):
        self.catia_app = catia_app
        self.dialog_window = dialog_window
        super().__init__(server_address, RequestHandlerClass)

    def convert_to_wrl(self, source_file, output_dir, output_name):
        """
        CATIA dosyasını WRL formatına dönüştür

        Args:
            source_file: Kaynak CATIA dosyası (.CATPart, .CATProduct, .STP vb.)
            output_dir: Çıktı klasörü
            output_name: Çıktı dosya adı (uzantısız)

        Returns:
            dict: {'output_file': 'tam/dosya/yolu.wrl', 'source_file': str, 'timestamp': str}
        """
        import pythoncom

        try:
            # COM Thread başlat (HTTP server farklı thread'de)
            pythoncom.CoInitialize()

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"Dönüştürme başladı: {source_file}")

            # CATIA uygulamasını al
            if not self.catia_app:
                raise Exception("CATIA bağlantısı yok!")

            # CATIA ayarları (TEST MODU)
            try:
                self.catia_app.DisplayFileAlerts = False  # Uyarıları kapat
                self.catia_app.Interactive = True         # İnteraktif modu AÇ
                if self.dialog_window:
                    self.dialog_window.log_signal.emit(f"ℹ CATIA Interactive mode: AÇIK")
            except:
                pass

            # IFikatia wrapper oluştur
            fikatia = IFikatia(obj=self.catia_app)

            # Dosyayı CATIA'da aç
            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"Dosya açılıyor: {source_file}")

            dokuman_listesi = fikatia.dokumanlar
            dokuman = dokuman_listesi.ac(source_file)

            if not dokuman:
                raise Exception(f"Dosya açılamadı: {source_file}")

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"✓ Dosya açıldı: {dokuman.ismi}")

            # Çıktı dosya yolunu oluştur
            output_file = os.path.join(output_dir, f"{output_name}.wrl")

            # WRL formatına dönüştür
            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"WRL export başlıyor...")

            dokuman_obj = IDokuman(obj=dokuman.catNesne, sahip=fikatia)
            dokuman_obj.veriAktar(output_file, "wrl")

            # Dökümanı KAPATMA (test için açık bırak)
            # dokuman.kapat()

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"✓ WRL oluşturuldu: {output_file}")
                self.dialog_window.log_signal.emit(f"ℹ Test modu: Döküman açık bırakıldı")

            return {
                'output_file': output_file,
                'source_file': source_file,
                'timestamp': datetime.now().isoformat()
            }

        except Exception as e:
            error_msg = f"✗ Hata: {str(e)}"

            if self.dialog_window:
                self.dialog_window.log_signal.emit(error_msg)

            raise

    def convert_to_wrl_batch(self, source_file, output_dir, output_name):
        """
        CATIA Batch Mode ile STP/STEP → WRL dönüştürme

        CATIA'yı bağımsız bir process olarak batch modunda başlatır.
        Mevcut CATIA oturumunu kullanmaz, yeni bir instance açar.

        Args:
            source_file: Kaynak STP/STEP dosyası
            output_dir: Çıktı klasörü
            output_name: Çıktı dosya adı (uzantısız)

        Returns:
            dict: {'output_file': str, 'source_file': str, 'method': 'batch', 'timestamp': str}
        """
        import subprocess

        try:
            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"[BATCH MODE] Dönüştürme başladı: {source_file}")

            # Çıktı dosya yolu
            output_file = os.path.join(output_dir, f"{output_name}.wrl")

            # Batch script ve macro yolları
            script_dir = os.path.dirname(os.path.abspath(__file__))
            batch_dir = os.path.join(script_dir, "CatiaBatch")
            macro_path = os.path.join(batch_dir, "ConvertMacro.catvbs")

            # Dosya varlık kontrolü
            if not os.path.exists(macro_path):
                raise FileNotFoundError(f"CATIA macro bulunamadı: {macro_path}")

            # CATIA yolu
            catia_path = r"C:\Program Files\Dassault Systemes\B20\win_b64\code\bin\CATSTART.exe"

            if not os.path.exists(catia_path):
                raise FileNotFoundError(f"CATIA bulunamadı: {catia_path}")

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"[BATCH] Macro: {macro_path}")
                self.dialog_window.log_signal.emit(f"[BATCH] CATIA: {catia_path}")
                self.dialog_window.log_signal.emit(f"[BATCH] CATIA başlatılıyor...")

            # CATIA'yı batch modunda çalıştır
            cmd = [
                catia_path,
                "-batch",
                "-run", "CNEXT.exe",
                "-macro", macro_path,
                source_file,
                output_file
            ]

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"[BATCH] Komut çalıştırılıyor...")

            # Process başlat ve bekle
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                creationflags=subprocess.CREATE_NO_WINDOW
            )

            # Process'in bitmesini bekle (timeout 120 saniye)
            try:
                stdout, stderr = process.communicate(timeout=120)

                if process.returncode != 0:
                    error_msg = stderr.decode('utf-8', errors='replace') if stderr else "Bilinmeyen hata"
                    raise Exception(f"CATIA batch process hatası (kod {process.returncode}): {error_msg[:200]}")

            except subprocess.TimeoutExpired:
                process.kill()
                raise Exception("CATIA batch process timeout (120 saniye)")

            # Çıktı dosyası kontrolü
            if not os.path.exists(output_file):
                # Log dosyasını kontrol et
                log_path = os.path.join(batch_dir, "conversion.log")
                log_content = ""
                if os.path.exists(log_path):
                    try:
                        with open(log_path, 'r', encoding='utf-8') as f:
                            log_content = f.read()[-500:]  # Son 500 karakter
                    except:
                        pass

                raise Exception(f"WRL dosyası oluşturulamadı. Log: {log_content[:200]}")

            file_size = os.path.getsize(output_file)

            if self.dialog_window:
                self.dialog_window.log_signal.emit(f"[BATCH] ✓ WRL oluşturuldu: {file_size:,} bytes")
                self.dialog_window.log_signal.emit(f"[BATCH] ✓ Dosya: {output_file}")

            return {
                'output_file': output_file,
                'source_file': source_file,
                'method': 'batch',
                'file_size': file_size,
                'timestamp': datetime.now().isoformat()
            }

        except Exception as e:
            error_msg = f"[BATCH] ✗ Hata: {str(e)}"

            if self.dialog_window:
                self.dialog_window.log_signal.emit(error_msg)

            raise


class IDialogCevirici(QMainWindow):
    """
    FikoYT Dialog Çevirici - CATIA WRL Dönüştürme Servisi

    HTTP Server ile CATIA dosyalarını WRL formatına dönüştürür.
    PyQt6 UI ile server durumunu ve logları gösterir.
    """

    log_signal = pyqtSignal(str)  # Log mesajları için sinyal

    def __init__(self, parent=None, flags=None, Catia=None):
        """
        Dialog constructor

        Args:
            parent: Parent widget (None - standalone)
            flags: Qt window flags
            Catia: CATIA COM Application nesnesi
        """
        # CATIA COM nesnesi kontrolü
        if Catia is None:
            raise ValueError("CATIA parametresi boş olamaz!")

        # PyQt6 initialization
        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

        super(IDialogCevirici, self).__init__(None)

        # CATIA COM nesnesi sarmalama
        self.__fikatia = IFikatia(obj=Catia)
        self.__catia_app = Catia

        # Script dosyasının yolu
        self.ScriptYolu = str(Path(__file__).parent)

        # Server değişkenleri
        self.server = None
        self.server_thread = None
        self.server_port = 1989
        self.server_running = False

        # UI oluştur (programatik olarak - .ui dosyası yoksa)
        self.init_ui()

        # Log sinyalini bağla
        self.log_signal.connect(self.append_log)

        # Pencere özelliklerini ayarla
        self.setWindowFlags(
            Qt.WindowType.Window |
            Qt.WindowType.WindowCloseButtonHint |
            Qt.WindowType.CustomizeWindowHint |
            Qt.WindowType.WindowStaysOnTopHint
        )

        self.setWindowTitle("FikoYT - Dialog Çevirici Server")
        self.resize(800, 600)

    def init_ui(self):
        """UI bileşenlerini oluştur"""
        # Ana widget
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # Ana layout
        main_layout = QVBoxLayout(central_widget)

        # Başlık
        title_label = QLabel("FikoYT Dialog Çevirici - WRL Dönüştürme Servisi")
        title_label.setStyleSheet("font-size: 18px; font-weight: bold; padding: 10px;")
        title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        main_layout.addWidget(title_label)

        # Server kontrol paneli
        control_layout = QHBoxLayout()

        # Port ayarı
        port_label = QLabel("Port:")
        control_layout.addWidget(port_label)

        self.port_spinbox = QSpinBox()
        self.port_spinbox.setRange(1024, 65535)
        self.port_spinbox.setValue(self.server_port)
        self.port_spinbox.valueChanged.connect(self.on_port_changed)
        control_layout.addWidget(self.port_spinbox)

        # Başlat butonu
        self.btn_start = QPushButton("Server Başlat")
        self.btn_start.clicked.connect(self.start_server)
        self.btn_start.setStyleSheet("background-color: #4CAF50; color: white; padding: 8px;")
        control_layout.addWidget(self.btn_start)

        # Durdur butonu
        self.btn_stop = QPushButton("Server Durdur")
        self.btn_stop.clicked.connect(self.stop_server)
        self.btn_stop.setEnabled(False)
        self.btn_stop.setStyleSheet("background-color: #f44336; color: white; padding: 8px;")
        control_layout.addWidget(self.btn_stop)

        control_layout.addStretch()
        main_layout.addLayout(control_layout)

        # Durum label
        self.status_label = QLabel("Durum: Server kapalı")
        self.status_label.setStyleSheet("padding: 10px; font-size: 14px; color: #666;")
        main_layout.addWidget(self.status_label)

        # Log alanı
        log_label = QLabel("Server Logları:")
        log_label.setStyleSheet("font-weight: bold; padding: 5px;")
        main_layout.addWidget(log_label)

        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setStyleSheet("background-color: #1e1e1e; color: #00ff00; font-family: monospace;")
        main_layout.addWidget(self.log_text)

        # Temizle butonu
        btn_clear_log = QPushButton("Logları Temizle")
        btn_clear_log.clicked.connect(self.clear_log)
        main_layout.addWidget(btn_clear_log)

    @pyqtSlot()
    def on_port_changed(self):
        """Port değiştiğinde"""
        if not self.server_running:
            self.server_port = self.port_spinbox.value()

    @pyqtSlot()
    def start_server(self):
        """HTTP Server'ı başlat"""
        try:
            if self.server_running:
                self.append_log("⚠ Server zaten çalışıyor!")
                return

            # Server'ı ayrı thread'de başlat
            @Async()
            def start_http_server(catia_app, port, dialog_window):
                try:
                    server_address = ('', port)
                    httpd = ThreadedHTTPServer(
                        server_address,
                        CeviriciRequestHandler,
                        catia_app=catia_app,
                        dialog_window=dialog_window
                    )

                    dialog_window.server = httpd
                    dialog_window.server_running = True

                    dialog_window.log_signal.emit(f"✓ Server başlatıldı: http://localhost:{port}")
                    dialog_window.log_signal.emit(f"  - Status: http://localhost:{port}/status")
                    dialog_window.log_signal.emit(f"  - Health: http://localhost:{port}/health")
                    dialog_window.log_signal.emit(f"  - Convert: POST http://localhost:{port}/convert")

                    # Server'ı çalıştır (blocking call)
                    httpd.serve_forever()

                except Exception as e:
                    dialog_window.log_signal.emit(f"✗ Server başlatma hatası: {str(e)}")
                    dialog_window.server_running = False

            # Thread'i başlat
            start_http_server(self.__catia_app, self.server_port, self)

            # UI güncelle
            self.btn_start.setEnabled(False)
            self.btn_stop.setEnabled(True)
            self.port_spinbox.setEnabled(False)
            self.status_label.setText(f"Durum: Server çalışıyor (Port: {self.server_port})")
            self.status_label.setStyleSheet("padding: 10px; font-size: 14px; color: #4CAF50; font-weight: bold;")

        except Exception as e:
            QMessageBox.critical(self, "Hata", f"Server başlatılamadı: {str(e)}")
            self.append_log(f"✗ Server başlatma hatası: {str(e)}")

    @pyqtSlot()
    def stop_server(self):
        """HTTP Server'ı durdur"""
        try:
            if not self.server_running:
                self.append_log("⚠ Server zaten durmuş!")
                return

            if self.server:
                self.server.shutdown()
                self.server = None
                self.server_running = False

                self.append_log("✓ Server durduruldu")

                # UI güncelle
                self.btn_start.setEnabled(True)
                self.btn_stop.setEnabled(False)
                self.port_spinbox.setEnabled(True)
                self.status_label.setText("Durum: Server kapalı")
                self.status_label.setStyleSheet("padding: 10px; font-size: 14px; color: #666;")

        except Exception as e:
            QMessageBox.critical(self, "Hata", f"Server durdurulamadı: {str(e)}")
            self.append_log(f"✗ Server durdurma hatası: {str(e)}")

    @pyqtSlot(str)
    def append_log(self, message):
        """Log mesajı ekle"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {message}"
        self.log_text.append(log_entry)

        # En alta scroll
        cursor = self.log_text.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.End)
        self.log_text.setTextCursor(cursor)

    @pyqtSlot()
    def clear_log(self):
        """Logları temizle"""
        self.log_text.clear()
        self.append_log("Loglar temizlendi")

    @pyqtSlot()
    def show(self):
        """Pencereyi göster"""
        super(IDialogCevirici, self).show()
        self.append_log("FikoYT Dialog Çevirici başlatıldı")
        self.append_log(f"CATIA bağlantısı: {'✓ Aktif' if self.__catia_app else '✗ Yok'}")

    def closeEvent(self, event):
        """Pencere kapatılırken"""
        if self.server_running:
            reply = QMessageBox.question(
                self,
                'Çıkış',
                "Server çalışıyor. Kapatmak istediğinizden emin misiniz?",
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
                QMessageBox.StandardButton.No
            )

            if reply == QMessageBox.StandardButton.Yes:
                self.stop_server()
                event.accept()
            else:
                event.ignore()
        else:
            event.accept()


if __name__ == '__main__':
    import win32com.client

    app = QApplication(sys.argv)
    app.setStyle("fusion")

    try:
        # CATIA'yı başlat
        catia = win32com.client.Dispatch("Catia.Application")

        # Dialog'u oluştur
        dialog = IDialogCevirici(Catia=catia)
        dialog.show()

        sys.exit(app.exec())

    except Exception as e:
        print(f"Hata: {e}")
        QMessageBox.critical(None, "Hata", f"CATIA bağlantısı kurulamadı: {str(e)}")
