from PIL import Image, ImageDraw, ImageFont, ImageEnhance
from .core import AncientScripts
import textwrap
import os
import datetime
import logging
from typing import Optional, Tuple, List
import hashlib

class AncientImageGenerator:
    """
    Generate an image with ancient script text overlay automatically.
    Uses the default background image inside the package,
    but saves the output in the USER PROJECT directory.

    Example:
        from ancient.visualizer import AncientImageGenerator

        gen = AncientImageGenerator(script='cuneiform')
        gen.generate_image("سلام دنیا")
        gen.generate_image("متن تست", output_filename="my_ancient_image.png")
    """

    def __init__(self, script="cuneiform", log_level=logging.INFO):
        self.converter = AncientScripts()
        self.script = script
        
        # تنظیم لاگر
        self.logger = logging.getLogger(f"AncientImageGenerator_{script}")
        self.logger.setLevel(log_level)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
        
        # کش فونت برای بهینه‌سازی
        self._font_cache = {}
        
        # مسیر فایل‌های پکیج
        self.package_dir = os.path.dirname(__file__)
        self.background_path = os.path.join(self.package_dir, "background.jpg")
        self.font_path = os.path.join(self.package_dir, "NotoSansCuneiform-Regular.ttf")
        
        # بررسی فایل‌ها در زمان ساخت
        self._check_files()

    def _check_files(self):
        """بررسی وجود فایل‌های مورد نیاز"""
        if not os.path.exists(self.background_path):
            raise FileNotFoundError("❌ background.jpg not found in package folder.")
        if not os.path.exists(self.font_path):
            raise FileNotFoundError("❌ Font file not found in package folder.")
        self.logger.info("✅ فایل‌های مورد نیاز با موفقیت یافت شدند")

    def _get_cached_font(self, font_path: str, size: int) -> ImageFont.FreeTypeFont:
        """دریافت فونت از کش با مدیریت خطا"""
        cache_key = f"{font_path}_{size}"
        
        if cache_key not in self._font_cache:
            try:
                font = ImageFont.truetype(font_path, size)
                # تست اعتبار فونت
                test_bbox = font.getbbox("A")
                if test_bbox[2] - test_bbox[0] <= 0:
                    raise ValueError("فونت نامعتبر است")
                self._font_cache[cache_key] = font
                self.logger.debug(f"فونت با سایز {size} در کش ذخیره شد")
            except Exception as e:
                self.logger.warning(f"خطا در بارگذاری فونت با سایز {size}: {e}")
                # استفاده از فونت پیش‌فرض سیستم
                self._font_cache[cache_key] = ImageFont.load_default()
        
        return self._font_cache[cache_key]

    def _get_text_size(self, font: ImageFont.FreeTypeFont, text: str) -> Tuple[int, int]:
        """محاسبه اندازه متن با مدیریت خطا"""
        try:
            bbox = font.getbbox(text)
            return bbox[2] - bbox[0], bbox[3] - bbox[1]
        except Exception as e:
            self.logger.error(f"خطا در محاسبه اندازه متن: {e}")
            return len(text) * 10, 20  # تخمین پیش‌فرض

    def _fit_text_optimized(self, text: str, max_width: int, max_height: int, 
                           min_font_size: int = 10, max_font_size: int = 200) -> Tuple[ImageFont.FreeTypeFont, List[str]]:
        """
        الگوریتم بهینه‌شده برای جا دادن حداکثر متن در تصویر
        استفاده از جستجوی دودویی برای پیدا کردن بهترین سایز فونت
        """
        self.logger.info(f"شروع بهینه‌سازی متن با ابعاد {max_width}x{max_height}")
        
        # محاسبه تعداد خطوط مناسب بر اساس طول متن
        base_line_length = max(20, max_width // 30)  # تخمین تعداد کاراکتر در هر خط
        wrapped = textwrap.wrap(text, width=base_line_length)
        
        # جستجوی دودویی برای پیدا کردن بهترین سایز
        low, high = min_font_size, max_font_size
        best_font = None
        best_lines = None
        best_size = min_font_size
        best_coverage = 0  # درصد پوشش صفحه
        
        while low <= high:
            mid = (low + high) // 2
            font = self._get_cached_font(self.font_path, mid)
            
            # محاسبه ابعاد با این سایز فونت
            line_heights = []
            line_widths = []
            
            for line in wrapped:
                w, h = self._get_text_size(font, line)
                line_widths.append(w)
                line_heights.append(h)
            
            total_height = sum(line_heights)
            max_line_width = max(line_widths) if line_widths else 0
            
            # محاسبه درصد پوشش صفحه
            width_coverage = min(100, (max_line_width / max_width) * 100)
            height_coverage = min(100, (total_height / max_height) * 100)
            coverage = (width_coverage + height_coverage) / 2
            
            self.logger.debug(f"سایز {mid}: پوشش {coverage:.1f}%")
            
            if total_height <= max_height and max_line_width <= max_width:
                # این سایز مناسب است - سعی می‌کنیم بزرگتر هم بشه
                best_font = font
                best_lines = wrapped
                best_size = mid
                best_coverage = coverage
                low = mid + 1
            else:
                # این سایز بزرگ است - باید کوچکتر بشه
                high = mid - 1
                
            # تنظیم مجدد wrap بر اساس سایز فونت
            if best_font:
                new_width = max(10, max_width // (mid // 5 + 1))
                if new_width != base_line_length:
                    base_line_length = new_width
                    wrapped = textwrap.wrap(text, width=base_line_length)
        
        # اگر هیچ سایز مناسبی پیدا نشد
        if not best_font:
            self.logger.warning("سایز مناسب پیدا نشد، استفاده از حداقل سایز")
            best_font = self._get_cached_font(self.font_path, min_font_size)
            best_lines = textwrap.wrap(text, width=10)
            best_coverage = 0
        
        self.logger.info(f"بهترین سایز: {best_size} با پوشش {best_coverage:.1f}%")
        return best_font, best_lines

    def _adjust_contrast(self, img, text_color: Tuple[int, int, int] = (0, 0, 0)):
        """تنظیم کنتراست متن با پس‌زمینه"""
        # تبدیل به مقیاس خاکستری برای تحلیل روشنایی
        gray = img.convert('L')
        avg_brightness = sum(gray.getdata()) / (img.size[0] * img.size[1])
        
        # اگر پس‌زمینه تیره است، متن را روشن کن
        if avg_brightness < 128:
            text_color = (255, 255, 255)  # سفید
            self.logger.debug("پس‌زمینه تیره، متن سفید انتخاب شد")
        
        return text_color

    def generate_image(self, text: str, output_filename: Optional[str] = None, 
                      rtl: bool = False, enhance_contrast: bool = True,
                      text_color: Optional[Tuple[int, int, int]] = None) -> str:
        """
        Convert text to ancient script and draw on image (output in user path).
        
        Args:
            text: متن ورودی برای تبدیل
            output_filename: نام فایل خروجی (اختیاری)
            rtl: آیا متن راست‌به‌چپ است؟
            enhance_contrast: تنظیم خودکار کنتراست
            text_color: رنگ متن (سه‌تایی RGB)
        
        Returns:
            مسیر فایل خروجی
        """
        self.logger.info(f"شروع ساخت تصویر برای متن: {text[:50]}...")
        
        # اعتبارسنجی ورودی
        if not text or not text.strip():
            raise ValueError("متن ورودی نمی‌تواند خالی باشد")

        # انتخاب متد تبدیل
        convert_func = getattr(self.converter, self.script, None)
        if not convert_func:
            raise ValueError(f"Unsupported script: {self.script}")
        
        self.logger.debug(f"تبدیل متن به خط {self.script}")
        ancient_text = convert_func(text)
        self.logger.debug(f"متن تبدیل شده: {ancient_text[:50]}...")

        # بارگذاری تصویر
        try:
            img = Image.open(self.background_path)
            self.logger.debug(f"تصویر با ابعاد {img.size} بارگذاری شد")
        except Exception as e:
            self.logger.error(f"خطا در بارگذاری تصویر: {e}")
            raise

        # کپی از تصویر برای ویرایش
        img = img.copy()
        draw = ImageDraw.Draw(img)
        width, height = img.size

        # تنظیم خودکار رنگ متن
        if text_color is None and enhance_contrast:
            text_color = self._adjust_contrast(img)
        elif text_color is None:
            text_color = (0, 0, 0)  # پیش‌فرض سیاه
        
        self.logger.debug(f"رنگ متن: {text_color}")

        # بهینه‌سازی و جا دادن متن
        font, lines = self._fit_text_optimized(
            ancient_text, 
            max_width=width - 100,  # حاشیه 50 پیکسل از هر طرف
            max_height=height - 100
        )

        # محاسبه مختصات مرکزی
        total_height = sum(self._get_text_size(font, line)[1] for line in lines)
        y_text = (height - total_height) // 2

        # رسم متن
        self.logger.debug(f"شروع رسم {len(lines)} خط")
        for i, line in enumerate(lines):
            line_width, line_height = self._get_text_size(font, line)
            
            if rtl:
                # برای متون راست‌به‌چپ
                x_text = width - line_width - ((width - line_width) // 2)
                self.logger.debug(f"خط {i+1} (RTL): x={x_text}, y={y_text}")
            else:
                # برای متون چپ‌به‌راست
                x_text = (width - line_width) // 2
                self.logger.debug(f"خط {i+1} (LTR): x={x_text}, y={y_text}")
            
            # رسم با سایه ملایم برای خوانایی بهتر
            if enhance_contrast:
                # سایه ملایم پشت متن
                shadow_color = (255 - text_color[0], 255 - text_color[1], 255 - text_color[2])
                draw.text((x_text+2, y_text+2), line, font=font, fill=shadow_color)
            
            draw.text((x_text, y_text), line, font=font, fill=text_color)
            y_text += line_height + 5  # فاصله بین خطوط

        # ساخت نام فایل خروجی
        user_dir = os.getcwd()
        
        if output_filename:
            # اگر کاربر اسم داده، از همون استفاده کن
            output_path = os.path.join(user_dir, output_filename)
            self.logger.debug(f"استفاده از نام فایل کاربر: {output_filename}")
        else:
            # والا با timestamp بساز
            timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            # استفاده از هش متن برای یکتایی بیشتر
            text_hash = hashlib.md5(text.encode('utf-8')).hexdigest()[:8]
            output_filename = f"ancient_{self.script}_{timestamp}_{text_hash}.png"
            output_path = os.path.join(user_dir, output_filename)
            self.logger.debug(f"نام فایل پیش‌فرض ساخته شد: {output_filename}")

        # ذخیره با کیفیت بالا
        try:
            img.save(output_path, format="PNG", quality=95, optimize=True)
            self.logger.info(f"✅ تصویر با موفقیت ذخیره شد: {output_path}")
        except Exception as e:
            self.logger.error(f"خطا در ذخیره تصویر: {e}")
            raise

        print(f"✅ تصویر با متن باستانی ساخته شد: {output_path}")
        return output_path

    def clear_font_cache(self):
        """پاک کردن کش فونت برای آزادسازی حافظه"""
        self._font_cache.clear()
        self.logger.info("کش فونت پاک شد")




