#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FreeCAD 3D Model Renderer & GIF Generator API
Parametrik 3D model render ve animasyon oluşturma aracı
"""

import sys, os, time, json, argparse
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass, asdict
from pathlib import Path

# 🔹 FreeCAD modülleri yükleniyor
if os.name == 'nt':  # Windows
    FREECAD_PATH = r"D:\__sistem__\ProgramFiles\FreeCAD\bin"
else:  # Linux (Docker)
    FREECAD_PATH = "/usr/lib/freecad-python3/lib"

if FREECAD_PATH not in sys.path:
    sys.path.append(FREECAD_PATH)

import FreeCAD
from FreeCAD import Base

# 🔹 GUI yükle
try:
    import FreeCADGui
    FreeCADGui.showMainWindow()
    import ImportGui
    print("[INFO] FreeCADGui loaded successfully", flush=True)
except Exception as e:
    print(f"[ERROR] FreeCADGui yüklenemedi: {e}", flush=True)
    sys.exit(1)

# Image processing libraries
try:
    from PIL import Image, ImageEnhance, ImageFilter, ImageDraw, ImageFont
    import numpy as np
    USE_PIL = True
except ImportError:
    import imageio.v2 as imageio
    USE_PIL = False


@dataclass
class RenderConfig:
    """Render ayarları"""
    width: int = 1920
    height: int = 1080
    background: str = "White"  # White, Black, Transparent
    view_type: str = "axonometric"  # axonometric, perspective, orthographic
    # Yeni profesyonel parametreler
    render_quality: str = "high"  # low, medium, high, ultra
    anti_aliasing: bool = True
    object_name: str = None


@dataclass
class AnimationConfig:
    """Animasyon ayarları"""
    enabled: bool = True
    num_frames: int = 36
    angle_step: int = 10
    duration: float = 0.08  # frame başına süre (saniye)
    pause_duration: float = 1.5  # dönüşler arası duraklama
    loop: int = 0  # 0=sonsuz, 1+=tekrar sayısı
    fps: int = 12

    # Dönüş ayarları
    yaw_enabled: bool = True  # Y ekseni (sağ-sol)
    pitch_enabled: bool = True  # X ekseni (yukarı-aşağı)
    roll_enabled: bool = False  # Z ekseni

    # Dönüş açıları
    yaw_range: Tuple[int, int] = (0, 360)
    pitch_range: Tuple[int, int] = (0, 360)
    roll_range: Tuple[int, int] = (0, 360)


@dataclass
class OutputConfig:
    """Çıktı ayarları"""
    output_dir: str = "."
    base_name: str = "render"
    save_png: bool = True
    save_gif: bool = True
    save_frames: bool = False  # Ara frameleri sakla
    gif_optimize: bool = True
    gif_quality: int = 85


@dataclass
class CameraConfig:
    """Kamera ayarları"""
    zoom_level: float = 1.0
    camera_position: Optional[Tuple[float, float, float]] = None
    look_at: Optional[Tuple[float, float, float]] = None


@dataclass
class PostProcessingConfig:
    """Post-processing ayarları"""
    # Filtreler
    edge_detection: bool = False
    sharpen: bool = True
    sharpen_intensity: float = 1.5
    smooth: bool = False
    smooth_radius: int = 2
    # Renk ayarları
    contrast: float = 1.2
    brightness: float = 1.0
    saturation: float = 1.1
    # Efektler
    ambient_occlusion: bool = False
    ao_intensity: float = 0.3
    shadow: bool = False
    shadow_offset_x: int = 10
    shadow_offset_y: int = 10
    shadow_blur: int = 5
    shadow_opacity: float = 0.5
    vignette: bool = False
    vignette_intensity: float = 0.5
    wireframe: bool = False
    wireframe_density: int = 10
    # Gelişmiş efektler
    depth_of_field: bool = False
    dof_focus_distance: float = 50
    dof_aperture: float = 2.8
    bloom: bool = False
    bloom_intensity: float = 0.5
    bloom_threshold: float = 0.8
    motion_blur: bool = False
    motion_blur_intensity: float = 0.5
    # Grid/Cetvel
    grid_overlay: bool = False
    grid_size: int = 10
    ruler_enabled: bool = False
    # Ortam
    fog: bool = False
    fog_density: float = 0.02
    fog_color: str = "#CCCCCC"


@dataclass
class LightingConfig:
    """Işıklandırma ayarları"""
    enabled: bool = True
    intensity: float = 1.0
    color: Tuple[int, int, int] = (255, 255, 200)


@dataclass
class MaterialConfig:
    """Malzeme ayarları"""
    metallic: float = 0.5
    roughness: float = 0.5
    reflection_intensity: float = 0.3
    normal_map_intensity: float = 1.0


@dataclass
class BackgroundConfig:
    """Arka plan ayarları"""
    gradient: bool = False
    gradient_color_1: str = "#F0F0FF"
    gradient_color_2: str = "#C8C8DC"


class FreeCADRenderer:
    """FreeCAD render motoru"""

    def __init__(self, input_file: str, render_cfg: RenderConfig,
                 anim_cfg: AnimationConfig, output_cfg: OutputConfig,
                 camera_cfg: CameraConfig,
                 post_cfg: Optional[PostProcessingConfig] = None,
                 lighting_cfg: Optional[LightingConfig] = None,
                 material_cfg: Optional[MaterialConfig] = None,
                 background_cfg: Optional[BackgroundConfig] = None):
        self.input_file = input_file
        self.render_cfg = render_cfg
        self.anim_cfg = anim_cfg
        self.output_cfg = output_cfg
        self.camera_cfg = camera_cfg
        self.post_cfg = post_cfg or PostProcessingConfig()
        self.lighting_cfg = lighting_cfg or LightingConfig()
        self.material_cfg = material_cfg or MaterialConfig()
        self.background_cfg = background_cfg or BackgroundConfig()

        self.doc = None
        self.view = None
        self.frames: List[str] = []

    def debug(self, msg: str, level: str = "INFO"):
        """Debug mesajı"""
        print(f"[{level}] {msg}", flush=True)

    def setup_document(self):
        """Doküman ve model kurulumu"""
        if not os.path.exists(self.input_file):
            raise FileNotFoundError(f"Girdi dosyası bulunamadı: {self.input_file}")

        # Doküman oluştur
        self.doc = FreeCAD.newDocument("AutoRender")
        self.debug("Yeni belge oluşturuldu")

        # STEP dosyası içe aktar
        ImportGui.insert(self.input_file, self.doc.Name)
        self.debug(f"Model içe aktarıldı: {self.input_file}")

    def setup_view(self):
        """Görünüm ayarları"""
        FreeCADGui.showMainWindow()
        FreeCADGui.ActiveDocument = FreeCADGui.getDocument(self.doc.Name)
        self.view = FreeCADGui.ActiveDocument.ActiveView

        # Debug: object_name değerini yazdır
        print(f"[DEBUG] Render config object_name: {self.render_cfg.object_name}", flush=True)

        # Eğer object_name varsa, sadece o nesneyi göster
        if self.render_cfg.object_name:
            print(f"[DEBUG] object_name belirlendi: {self.render_cfg.object_name}", flush=True)
            
            # Tüm nesneleri gizle
            for obj in self.doc.Objects:
                obj.ViewObject.Visibility = False
                print(f"[DEBUG] Nesne gizlendi: {obj.Name}", flush=True)
            
            # Belirtilen nesneyi göster
            try:
                target_obj = self.doc.getObject(self.render_cfg.object_name)
                if target_obj:
                    target_obj.ViewObject.Visibility = True
                    print(f"[DEBUG] Nesne gösterildi: {target_obj.Name}", flush=True)
                    self.debug(f"Yalnızca nesne gösteriliyor: {self.render_cfg.object_name}")
                else:
                    self.debug(f"Nesne bulunamadı: {self.render_cfg.object_name}", "WARNING")
                    # Nesne bulunamazda tüm nesneleri göster
                    for obj in self.doc.Objects:
                        obj.ViewObject.Visibility = True
            except Exception as e:
                self.debug(f"Nesne gösterilemedi: {e}", "WARNING")
                # Hata durumunda tüm nesneleri göster
                for obj in self.doc.Objects:
                    obj.ViewObject.Visibility = True
        else:
            print("[DEBUG] object_name belirtilmedi, tüm nesneler gösterilecek", flush=True)
            self.debug("Tüm nesneler gösterilecek (object_name belirtilmedi)")

        # View type ayarla
        if self.render_cfg.view_type == "axonometric":
            self.view.viewAxonometric()
        elif self.render_cfg.view_type == "perspective":
            self.view.viewPerspective()
        elif self.render_cfg.view_type == "orthographic":
            self.view.viewOrthographic()

        # Kamera pozisyonu
        if self.camera_cfg.camera_position:
            self.view.setCameraOrientation(
                FreeCAD.Rotation(*self.camera_cfg.camera_position)
            )

        self.view.fitAll()

        # Zoom ayarı
        if self.camera_cfg.zoom_level != 1.0:
            cam = self.view.getCameraNode()
            if cam:
                try:
                    if hasattr(cam, 'heightAngle'):
                        current_height = cam.heightAngle.getValue()
                        new_height = current_height / self.camera_cfg.zoom_level
                        cam.heightAngle.setValue(new_height)
                    elif hasattr(cam, 'height'):
                        current_height = cam.height.getValue()
                        new_height = current_height / self.camera_cfg.zoom_level
                        cam.height.setValue(new_height)
                except:
                    pass  # Sessizce devam et

        FreeCADGui.updateGui()
        self.debug(f"Görünüm ayarlandı (zoom: {self.camera_cfg.zoom_level}x)")

    def render_static_image(self) -> str:
        """Statik görüntü render et"""
        if not self.output_cfg.save_png:
            return None

        output_file = os.path.join(
            self.output_cfg.output_dir,
            f"{self.output_cfg.base_name}.png"
        )

        self.view.saveImage(
            output_file,
            self.render_cfg.width,
            self.render_cfg.height,
            self.render_cfg.background
        )

        self.debug(f"Statik görüntü kaydedildi: {output_file}")
        return output_file

    def create_rotation_frames(self, axis: str, angle_range: Tuple[int, int]) -> List[str]:
        """Belirli eksen için dönüş frameleri oluştur"""
        frames = []
        start_angle, end_angle = angle_range

        num_frames = int((end_angle - start_angle) / self.anim_cfg.angle_step)

        self.debug(f"{axis.upper()} ekseni dönüş frameleri oluşturuluyor ({num_frames} frame)...")

        for i in range(num_frames):
            angle = start_angle + (i * self.anim_cfg.angle_step)

            # Eksen vektörü belirle
            if axis == "yaw":
                rotation = FreeCAD.Rotation(Base.Vector(0, 1, 0), angle)
            elif axis == "pitch":
                rotation = FreeCAD.Rotation(Base.Vector(1, 0, 0), angle)
            elif axis == "roll":
                rotation = FreeCAD.Rotation(Base.Vector(0, 0, 1), angle)
            else:
                continue

            self.view.setCameraOrientation(rotation)
            self.view.fitAll()

            # Zoom'u her frame'de yeniden uygula
            if self.camera_cfg.zoom_level != 1.0:
                cam = self.view.getCameraNode()
                if cam:
                    try:
                        if hasattr(cam, 'heightAngle'):
                            current_height = cam.heightAngle.getValue()
                            new_height = current_height / self.camera_cfg.zoom_level
                            cam.heightAngle.setValue(new_height)
                        elif hasattr(cam, 'height'):
                            current_height = cam.height.getValue()
                            new_height = current_height / self.camera_cfg.zoom_level
                            cam.height.setValue(new_height)
                    except:
                        pass  # Sessizce devam et

            FreeCADGui.updateGui()
            time.sleep(0.05)

            frame_file = os.path.join(
                self.output_cfg.output_dir,
                f"frame_{axis}_{i:04d}.png"
            )

            self.view.saveImage(
                frame_file,
                self.render_cfg.width,
                self.render_cfg.height,
                self.render_cfg.background
            )

            frames.append(frame_file)

            if (i + 1) % 10 == 0:
                self.debug(f"  Frame {i+1}/{num_frames} ({axis.upper()})")

        return frames

    def create_pause_frames(self, count: int) -> List[str]:
        """Duraklama frameleri oluştur"""
        frames = []
        for i in range(count):
            frame_file = os.path.join(
                self.output_cfg.output_dir,
                f"frame_pause_{i:04d}.png"
            )
            self.view.saveImage(
                frame_file,
                self.render_cfg.width,
                self.render_cfg.height,
                self.render_cfg.background
            )
            frames.append(frame_file)
        return frames

    def create_animation(self) -> Optional[str]:
        """GIF animasyonu oluştur"""
        if not self.anim_cfg.enabled or not self.output_cfg.save_gif:
            return None

        self.debug("Animasyon frameleri oluşturuluyor...")
        self.frames = []

        # YAW (Y ekseni - sağ-sol)
        if self.anim_cfg.yaw_enabled:
            yaw_frames = self.create_rotation_frames("yaw", self.anim_cfg.yaw_range)
            self.frames.extend(yaw_frames)

            # Duraklama
            pause_count = int(self.anim_cfg.pause_duration * self.anim_cfg.fps)
            pause_frames = self.create_pause_frames(pause_count)
            self.frames.extend(pause_frames)

        # PITCH (X ekseni - yukarı-aşağı)
        if self.anim_cfg.pitch_enabled:
            pitch_frames = self.create_rotation_frames("pitch", self.anim_cfg.pitch_range)
            self.frames.extend(pitch_frames)

            # Duraklama
            if self.anim_cfg.roll_enabled:
                pause_count = int(self.anim_cfg.pause_duration * self.anim_cfg.fps)
                pause_frames = self.create_pause_frames(pause_count)
                self.frames.extend(pause_frames)

        # ROLL (Z ekseni)
        if self.anim_cfg.roll_enabled:
            roll_frames = self.create_rotation_frames("roll", self.anim_cfg.roll_range)
            self.frames.extend(roll_frames)

        # GIF oluştur
        gif_path = os.path.join(
            self.output_cfg.output_dir,
            f"{self.output_cfg.base_name}.gif"
        )

        self.save_gif(gif_path)

        # Ara frameleri temizle
        if not self.output_cfg.save_frames:
            self.cleanup_frames()

        return gif_path

    def save_gif(self, output_path: str):
        """GIF'i kaydet (PIL veya imageio kullanarak)"""
        self.debug(f"GIF oluşturuluyor ({len(self.frames)} frame)...")

        if USE_PIL:
            self._save_gif_pil(output_path)
        else:
            self._save_gif_imageio(output_path)

    def _save_gif_pil(self, output_path: str):
        """PIL kullanarak GIF kaydet"""
        images = []

        self.debug("Frame'ler yükleniyor ve post-processing uygulanıyor...")

        for i, f in enumerate(self.frames):
            if not os.path.exists(f):
                continue

            img = Image.open(f)

            # Post-processing uygula
            img = self.apply_post_processing(img)

            images.append(img)

            if (i + 1) % 10 == 0:
                self.debug(f"  Post-processing: {i+1}/{len(self.frames)} frame işlendi")

        if not images:
            raise ValueError("Hiç frame oluşturulamadı!")

        self.debug(f"Toplam {len(images)} frame işlendi, GIF oluşturuluyor...")

        # GIF kaydet
        images[0].save(
            output_path,
            save_all=True,
            append_images=images[1:],
            duration=int(self.anim_cfg.duration * 1000),  # milisaniye
            loop=self.anim_cfg.loop,
            optimize=self.output_cfg.gif_optimize,
            quality=self.output_cfg.gif_quality
        )

        self.debug(f"GIF oluşturuldu (PIL): {output_path}")

    def _save_gif_imageio(self, output_path: str):
        """imageio kullanarak GIF kaydet"""
        images = [imageio.imread(f) for f in self.frames if os.path.exists(f)]

        if not images:
            raise ValueError("Hiç frame oluşturulamadı!")

        imageio.mimsave(
            output_path,
            images,
            duration=self.anim_cfg.duration,
            loop=self.anim_cfg.loop,
            subrectangles=True
        )

        self.debug(f"GIF oluşturuldu (imageio): {output_path}")

    def apply_post_processing(self, img: Image.Image) -> Image.Image:
        """Post-processing efektlerini uygula"""
        if not USE_PIL:
            return img

        cfg = self.post_cfg

        # 1. Sharpen (Keskinleştirme)
        if cfg.sharpen:
            enhancer = ImageEnhance.Sharpness(img)
            img = enhancer.enhance(cfg.sharpen_intensity)

        # 2. Smooth (Yumuşatma)
        if cfg.smooth:
            img = img.filter(ImageFilter.GaussianBlur(radius=cfg.smooth_radius))

        # 3. Contrast (Kontrast)
        if cfg.contrast != 1.0:
            enhancer = ImageEnhance.Contrast(img)
            img = enhancer.enhance(cfg.contrast)

        # 4. Brightness (Parlaklık)
        if cfg.brightness != 1.0:
            enhancer = ImageEnhance.Brightness(img)
            img = enhancer.enhance(cfg.brightness)

        # 5. Saturation (Doygunluk)
        if cfg.saturation != 1.0:
            enhancer = ImageEnhance.Color(img)
            img = enhancer.enhance(cfg.saturation)

        # 6. Edge Detection (Kenar Algılama)
        if cfg.edge_detection:
            edges = img.filter(ImageFilter.FIND_EDGES)
            img = Image.blend(img, edges, 0.5)

        # 7. Vignette (Köşe Karartma)
        if cfg.vignette:
            img = self._apply_vignette(img, cfg.vignette_intensity)

        # 8. Shadow (Gölge Efekti)
        if cfg.shadow:
            img = self._apply_shadow(img, cfg.shadow_offset_x, cfg.shadow_offset_y,
                                     cfg.shadow_blur, cfg.shadow_opacity)

        # 9. Grid Overlay (Izgara)
        if cfg.grid_overlay:
            img = self._apply_grid(img, cfg.grid_size, cfg.ruler_enabled)

        # 10. Bloom (Parıltı)
        if cfg.bloom:
            img = self._apply_bloom(img, cfg.bloom_intensity, cfg.bloom_threshold)

        # 11. Fog (Sis)
        if cfg.fog:
            img = self._apply_fog(img, cfg.fog_density, cfg.fog_color)

        return img

    def _apply_vignette(self, img: Image.Image, intensity: float) -> Image.Image:
        """Vignette efekti uygula"""
        width, height = img.size

        # Radial gradient oluştur
        vignette = Image.new('L', (width, height), 0)
        draw = ImageDraw.Draw(vignette)

        # Merkez ve radius
        center_x, center_y = width // 2, height // 2
        max_radius = min(width, height) // 2

        # Gradient çiz
        for i in range(max_radius, 0, -1):
            alpha = int(255 * (1 - (i / max_radius) * intensity))
            bbox = [center_x - i, center_y - i, center_x + i, center_y + i]
            draw.ellipse(bbox, fill=alpha)

        # Uygula
        img = img.convert('RGBA')
        vignette = vignette.convert('RGBA')
        return Image.composite(img, Image.new('RGBA', img.size, (0, 0, 0, 255)), vignette)

    def _apply_shadow(self, img: Image.Image, offset_x: int, offset_y: int,
                      blur: int, opacity: float) -> Image.Image:
        """Gölge efekti ekle"""
        # Gölge layer oluştur
        shadow = Image.new('RGBA', img.size, (0, 0, 0, 0))

        # Gölgeyi çiz (basit versiyonu - nesneyi offset ile tekrar çiz)
        shadow.paste(img, (offset_x, offset_y))
        shadow = shadow.filter(ImageFilter.GaussianBlur(blur))

        # Opacity ayarla
        alpha = shadow.split()[3]
        alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
        shadow.putalpha(alpha)

        # Birleştir
        result = Image.alpha_composite(shadow, img.convert('RGBA'))
        return result

    def _apply_grid(self, img: Image.Image, grid_size: int, ruler: bool) -> Image.Image:
        """Grid overlay ekle"""
        img = img.convert('RGBA')
        overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
        draw = ImageDraw.Draw(overlay)

        width, height = img.size

        # Grid çizgileri (açık gri)
        grid_color = (200, 200, 200, 128)

        # Dikey çizgiler
        for x in range(0, width, grid_size):
            draw.line([(x, 0), (x, height)], fill=grid_color, width=1)

        # Yatay çizgiler
        for y in range(0, height, grid_size):
            draw.line([(0, y), (width, y)], fill=grid_color, width=1)

        # Ruler (cetvel) - ana eksenleri kalın çiz
        if ruler:
            ruler_color = (255, 100, 100, 180)
            center_x, center_y = width // 2, height // 2

            # X ekseni (kırmızı)
            draw.line([(0, center_y), (width, center_y)], fill=ruler_color, width=2)

            # Y ekseni (kırmızı)
            draw.line([(center_x, 0), (center_x, height)], fill=ruler_color, width=2)

        return Image.alpha_composite(img, overlay)

    def _apply_bloom(self, img: Image.Image, intensity: float, threshold: float) -> Image.Image:
        """Bloom efekti (parıltı)"""
        # Parlak alanları bul
        enhancer = ImageEnhance.Brightness(img)
        bright = enhancer.enhance(2.0)

        # Threshold uygula
        bright_np = np.array(bright)
        threshold_val = int(threshold * 255)
        mask = np.all(bright_np > threshold_val, axis=-1) if bright_np.ndim == 3 else bright_np > threshold_val

        # Blur uygula
        bloom = bright.filter(ImageFilter.GaussianBlur(radius=15))

        # Orijinal ile blend et
        result = Image.blend(img, bloom, intensity * 0.5)
        return result

    def _apply_fog(self, img: Image.Image, density: float, color_hex: str) -> Image.Image:
        """Sis efekti"""
        # Hex rengi RGB'ye çevir
        color_hex = color_hex.lstrip('#')
        fog_color = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))

        # Sis layer oluştur
        fog_layer = Image.new('RGB', img.size, fog_color)

        # Blend et
        result = Image.blend(img.convert('RGB'), fog_layer, density)
        return result

    def cleanup_frames(self):
        """Ara frameleri temizle"""
        self.debug("Ara frameler temizleniyor...")
        for frame in self.frames:
            if os.path.exists(frame):
                try:
                    os.remove(frame)
                except Exception as e:
                    self.debug(f"Frame silinemedi {frame}: {e}", "WARNING")

    def render(self) -> Dict[str, str]:
        """Tüm render işlemini gerçekleştir"""
        results = {}

        try:
            self.setup_document()
            self.setup_view()

            # Statik görüntü
            png_path = self.render_static_image()
            if png_path:
                results['png'] = png_path

            # Animasyon
            gif_path = self.create_animation()
            if gif_path:
                results['gif'] = gif_path

            self.debug("İşlem başarıyla tamamlandı!", "SUCCESS")

        except Exception as e:
            self.debug(f"HATA: {e}", "ERROR")
            raise

        return results


def load_config_from_json(json_path: str) -> Dict:
    """JSON'dan konfigürasyon yükle"""
    with open(json_path, 'r', encoding='utf-8') as f:
        return json.load(f)


def save_config_template(output_path: str):
    """Örnek konfigürasyon şablonu oluştur"""
    config = {
        "input_file": "model.stp",
        "render": asdict(RenderConfig()),
        "animation": asdict(AnimationConfig()),
        "output": asdict(OutputConfig()),
        "camera": asdict(CameraConfig())
    }

    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2, ensure_ascii=False)

    print(f"Konfigürasyon şablonu oluşturuldu: {output_path}")


def main():
    parser = argparse.ArgumentParser(
        description="FreeCAD 3D Model Renderer & GIF Generator API"
    )

    parser.add_argument('input_file', nargs='?', help='STEP dosya yolu (.stp)')
    parser.add_argument('-c', '--config', help='JSON konfigürasyon dosyası')
    parser.add_argument('-o', '--output', help='Çıktı dizini')
    parser.add_argument('--width', type=int, help='Görüntü genişliği')
    parser.add_argument('--height', type=int, help='Görüntü yüksekliği')
    parser.add_argument('--frames', type=int, help='Animasyon frame sayısı')
    parser.add_argument('--fps', type=int, help='Animasyon FPS')
    parser.add_argument('--no-gif', action='store_true', help='GIF oluşturma')
    parser.add_argument('--no-png', action='store_true', help='PNG kaydetme')
    parser.add_argument('--save-frames', action='store_true', help='Ara frameleri sakla')
    parser.add_argument('--create-config', help='Örnek config.json oluştur')

    args = parser.parse_args()

    # Config şablonu oluştur
    if args.create_config:
        save_config_template(args.create_config)
        return

    # Varsayılan değerler
    if args.config:
        # JSON'dan yükle
        config_data = load_config_from_json(args.config)
        input_file = config_data.get('input_file', args.input_file)
        render_cfg = RenderConfig(**config_data.get('render', {}))
        anim_cfg = AnimationConfig(**config_data.get('animation', {}))
        output_cfg = OutputConfig(**config_data.get('output', {}))
        camera_cfg = CameraConfig(**config_data.get('camera', {}))
        post_cfg = PostProcessingConfig(**config_data.get('post_processing', {}))
        lighting_cfg = LightingConfig(**config_data.get('lighting', {}))
        material_cfg = MaterialConfig(**config_data.get('material', {}))
        background_cfg = BackgroundConfig(**config_data.get('background', {}))
    else:
        # Varsayılan + CLI argümanları
        input_file = args.input_file or r"D:\__sistem__\ProgramFiles\FreeCAD\bin\freecad.stp"
        render_cfg = RenderConfig()
        anim_cfg = AnimationConfig()
        output_cfg = OutputConfig()
        camera_cfg = CameraConfig()
        post_cfg = PostProcessingConfig()
        lighting_cfg = LightingConfig()
        material_cfg = MaterialConfig()
        background_cfg = BackgroundConfig()

    # CLI override
    if args.output:
        output_cfg.output_dir = args.output
    if args.width:
        render_cfg.width = args.width
    if args.height:
        render_cfg.height = args.height
    if args.frames:
        anim_cfg.num_frames = args.frames
    if args.fps:
        anim_cfg.fps = args.fps
    if args.no_gif:
        output_cfg.save_gif = False
    if args.no_png:
        output_cfg.save_png = False
    if args.save_frames:
        output_cfg.save_frames = True

    # Çıktı dizini oluştur
    os.makedirs(output_cfg.output_dir, exist_ok=True)

    # Render et
    renderer = FreeCADRenderer(
        input_file,
        render_cfg,
        anim_cfg,
        output_cfg,
        camera_cfg,
        post_cfg,
        lighting_cfg,
        material_cfg,
        background_cfg
    )

    results = renderer.render()

    # Sonuçları yazdır
    print("\n" + "="*60)
    print("RENDER TAMAMLANDI")
    print("="*60)
    for key, path in results.items():
        print(f"{key.upper()}: {path}")
    print("="*60)


if __name__ == "__main__":
    main()
