#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import argparse
from PIL import Image
import concurrent.futures
import time

# --- 1. 复制自您脚本中的 CPU 核心数检测逻辑 ---
try:
    DEFAULT_WORKERS = os.cpu_count() or 1
except AttributeError:
    try:
        import multiprocessing
        DEFAULT_WORKERS = multiprocessing.cpu_count()
    except (ImportError, NotImplementedError):
        DEFAULT_WORKERS = 4

# --- 2. 定义支持的图片格式 ---
SUPPORTED_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff', '.tif')

# --- 3. 确定Pillow的重采样过滤器 ---
try:
    RESAMPLE_FILTER = Image.Resampling.LANCZOS
except AttributeError:
    RESAMPLE_FILTER = Image.LANCZOS


def _process_single_image(image_path, target_min_side):
    """
    工作函数：处理单个文件的缩放。（此函数与上一版完全相同）
    
    :param image_path: 完整图片路径
    :param target_min_side: 目标最小边长 (例如 1080)
    :return: (状态, 原始文件名, 结果/错误信息)
    """
    filename = os.path.basename(image_path)
    
    try:
        with Image.open(image_path) as img:
            img_info = img.info.copy()
            width, height = img.size
            min_side = min(width, height)

            # --- 核心逻辑：检查是否需要缩放 ---
            if min_side <= target_min_side:
                # 返回相对路径以便于阅读
                return "skipped", image_path, f"最小边 ({min_side}px) 已 <= {target_min_side}px"

            # --- 计算新尺寸 ---
            scale_ratio = target_min_side / min_side
            new_width = int(width * scale_ratio)
            new_height = int(height * scale_ratio)

            # --- 执行缩放 ---
            resized_img = img.resize((new_width, new_height), RESAMPLE_FILTER)
            
            # --- 覆盖保存 ---
            resized_img.save(image_path, **img_info)

            # 返回相对路径以便于阅读
            return "success", image_path, f"从 {width}x{height} -> {new_width}x{new_height}"

    except Exception as e:
        # 返回相对路径以便于阅读
        return "fail", image_path, str(e)

def resize_images_in_folder(folder_path, target_min_side=1080, max_workers=DEFAULT_WORKERS):
    """
    *** [已更新] ***
    批量将文件夹及其所有子文件夹中最小边 > target_min_side 的图片等比例缩小。

    :param folder_path: 目标根文件夹路径
    :param target_min_side: 目标最小边长
    :param max_workers: 使用的进程数
    """

    if not os.path.isdir(folder_path):
        print(f"错误：文件夹 '{folder_path}' 不存在或不是一个有效的目录。")
        return

    print(f"--- 开始 **递归** 处理文件夹: {folder_path} ---")
    print(f"--- 目标最小边: {target_min_side}px ---")
    print(f"--- 使用最多 {max_workers} 个进程并行处理 ---")
    
    start_time = time.time()

    # --- 1. 收集所有需要处理的任务 (*** [核心修改] ***) ---
    tasks = []
    print("--- 正在递归扫描所有子文件夹... ---")
    
    # 使用 os.walk 递归遍历
    for dirpath, dirnames, filenames in os.walk(folder_path):
        for filename in filenames:
            # 检查文件扩展名是否在支持的列表中
            if filename.lower().endswith(SUPPORTED_EXTENSIONS):
                # 构造完整的文件路径
                image_path = os.path.join(dirpath, filename)
                tasks.append((image_path, target_min_side))

    if not tasks:
        print(f"未在 {folder_path} 及其子文件夹中找到支持的图片文件。")
        return

    print(f"--- 发现 {len(tasks)} 个图片文件，开始处理... ---")

    resized_count = 0
    skipped_count = 0
    failed_count = 0
    
    # 转换为相对路径，使输出更简洁
    base_folder_path = os.path.abspath(folder_path)

    # --- 2. 使用 ProcessPoolExecutor 执行任务 (与上一版相同) ---
    with concurrent.futures.ProcessPoolExecutor(max_workers=max_workers) as executor:
        future_to_path = {
            executor.submit(_process_single_image, path, size): path
            for path, size in tasks
        }

        # --- 3. 实时获取已完成的结果 (与上一版相同) ---
        for future in concurrent.futures.as_completed(future_to_path):
            try:
                # status, path_or_name, result
                status, image_path, result = future.result()
                
                # 转换为相对路径
                try:
                    display_path = os.path.relpath(image_path, base_folder_path)
                except ValueError:
                    display_path = image_path # 如果不在同一驱动器(Windows)，则显示完整路径

                if status == "success":
                    print(f"  [成功] {display_path}: {result}")
                    resized_count += 1
                elif status == "skipped":
                    print(f"  [跳过] {display_path}: {result}")
                    skipped_count += 1
                elif status == "fail":
                    print(f"  [失败] {display_path}: {result}")
                    failed_count += 1
                    
            except Exception as e:
                orig_path = future_to_path[future]
                print(f"  [严重失败] 处理 {orig_path} 时进程出错: {e}")
                failed_count += 1

    end_time = time.time()
    print("--- 处理完毕 ---")
    if resized_count > 0:
        print(f"成功缩放 {resized_count} 个文件。")
    if skipped_count > 0:
        print(f"跳过 {skipped_count} 个文件 (无需缩放)。")
    if failed_count > 0:
        print(f"失败 {failed_count} 个文件。")
    print(f"总耗时: {end_time - start_time:.2f} 秒。")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="*** [已更新] *** 批量 **递归** 缩放文件夹及其子文件夹中的图片，使最小边不超过指定值。"
    )
    
    # 位置参数：文件夹路径 (必需)
    parser.add_argument(
        "folder",
        type=str,
        help="包含图片的 **根** 文件夹路径 (例如 ./MyImages)，将递归处理所有子文件夹。"
    )
    
    # 选项参数：目标尺寸 (可选)
    parser.add_argument(
        "-s", "--size",
        type=int,
        default=1080,
        help="指定目标最小边长 (默认: 1080)。如果图片最小边已小于此值，则跳过。"
    )
    
    # 选项参数：控制进程数 (可选)
    parser.add_argument(
        "-w", "--workers",
        type=int,
        default=DEFAULT_WORKERS,
        help=f"指定用于转换的工作进程数 (默认: {DEFAULT_WORKERS}, 即本机CPU核心数)"
    )
    
    args = parser.parse_args()
    
    # 将文件夹路径、"目标尺寸" 和 "工作进程数" 传递给函数
    resize_images_in_folder(args.folder, args.size, args.workers)