from patch.include import *
from tqdm import tqdm
from PIL import Image, UnidentifiedImageError
import tempfile
import logging

# Настроим логирование
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

@app_context(commit=True)
def fix_review_png():
    """
    Оптимизированная версия обработки превью изображений.
    """
    logging.info('Запуск патча fix_review_png')
    MAX_WIDTH = 1024  # Параметризуемая ширина
    JPEG_QUALITY = 20  # Качество JPEG для миниатюры
    MAX_THUMBNAIL_SIZE = 130 * 1024  # Максимальный размер 130Кб
    rdisk = models.CmfRFile.dp.data_driver.get_rd()
    cnt = models.CmfAttachment.count()
    step = 1000
    i = 0
    
    while cnt > 0:
        for attach in tqdm(models.CmfAttachment.list(slice=[i * step, i * step + step]), desc=f'Batch {i + 1}'):
            try:
                rfile = rdisk.get_rfile(attach._file_name)
                preview_converted_flag_id = os.path.join(f"{rfile.id}.meta", "preview_converted_flag")
                preview_converted = rdisk.get_rfile(preview_converted_flag_id)
                if preview_converted.exists:
                    continue
                
                thumbnail_path = os.path.join(rfile.meta_path, "thumbnail.jpg")
                thumbnail_id = os.path.join(f"{rfile.id}.meta", "thumbnail.jpg")
                preview_id = os.path.join(f"{rfile.id}.meta", "preview_img.png")
                preview_delme_id = os.path.join(f"{rfile.id}.meta", "preview_img.png.delme")
                preview = rdisk.get_rfile(os.path.join(f"{rfile.id}.meta", 'preview_img.png'))
                                          
                if not preview.exists:
                    logging.warning(f"Превью отсутствует: {preview_id}")
                    continue
                
                with Image.open(preview.tmp_readonly_path) as img:
                    if img.width <= MAX_WIDTH and Path(preview.tmp_readonly_path).stat().st_size <= MAX_THUMBNAIL_SIZE:
                        logging.info(f"Файл {preview_id} уже подходит по параметрам, пропускаем")
                        continue
                    
                    if img.mode in ("RGBA", "P"):
                        img = img.convert("RGB")
                    
                    # Оптимизированное уменьшение изображения
                    if img.width > MAX_WIDTH:
                        img.thumbnail((MAX_WIDTH, img.height), Image.Resampling.LANCZOS)
                    
                    with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_file:
                        temp_path = Path(temp_file.name)
                        img.save(temp_path, format="JPEG", quality=100, optimize=True)
                        
                        # Если больше максимального размера, повторяем с более низким качеством
                        if temp_path.stat().st_size > MAX_THUMBNAIL_SIZE:
                            img.save(temp_path, format="JPEG", quality=JPEG_QUALITY, optimize=True)
                        
                        rdisk.io.io_write_bytes(thumbnail_path, temp_path.read_bytes())
                        logging.info(f"Сохранена миниатюра: {thumbnail_path}")
                    
                    temp_path.unlink(missing_ok=True)
                    thumbnail = rdisk.get_rfile(thumbnail_id)
                    preview.rename(preview_delme_id)
                    thumbnail.rename(preview_id)
                
                # Записываем флаг обработки
                rdisk.io.io_write_bytes(preview_converted.path, b'')
            
            except UnidentifiedImageError:
                logging.exception(f"Ошибка: файл {preview_id} не является изображением.")
            except IOError as e:
                logging.exception(f"Ошибка обработки {preview_id}: {e}")
            except Exception as e:
                logging.exception(f"Неизвестная ошибка с файлом {preview_id}: {e}")
        
        i += 1
        cnt -= step
    
    logging.info('Завершение работы fix_review_png')
    logging.info('После подтверждения от клиента удалите старые превью с именами preview_img.png.delme')

if __name__ == "__main__":
    fix_review_png()
