# pip install pillow
"""
yjm_img_to_banner_ratio_fix.py

사용자가 원하는 방식:
- 목표 최대 크기: 600 x 166
- 원본 비율 유지
- 원본 절대 크롭 안 함
- 여백용 600x166 캔버스 만들지 않음
- 가로/세로 중 더 많이 줄여야 하는 쪽에 맞춰 전체를 동일 비율로 축소
- 작은 이미지는 확대하지 않음
- PNG는 RGBA truecolor로 저장
- 결과 크기는 비율에 따라 600x166보다 작을 수 있음

예)
원본 2172 x 724
가로 배율 = 600 / 2172 = 0.2762
세로 배율 = 166 / 724  = 0.2293
더 작은 배율 0.2293 적용
=> 결과 약 498 x 166

즉:
- 잘림 없음
- 찌그러짐 없음
- 강제 여백 없음
- 단, 원본 비율이 600:166과 다르면 결과가 정확히 600x166은 아닐 수 있음
"""

import sys
from pathlib import Path
from PIL import Image
import tkinter as tk
from tkinter import filedialog, messagebox

SUPPORTED = {".png", ".jpg", ".jpeg", ".webp"}

MAX_W = 600
MAX_H = 166


def normalize_path(text: str) -> str:
    text = text.strip().strip('"').strip("'")
    if text.startswith("{") and text.endswith("}"):
        text = text[1:-1]
    return text


def gather_images(paths):
    result = []
    seen = set()

    for raw in paths:
        p = Path(normalize_path(str(raw)))

        if not p.exists():
            print(f"[경고] 없는 경로: {p}")
            continue

        if p.is_file():
            if p.suffix.lower() in SUPPORTED:
                rp = p.resolve()
                if rp not in seen:
                    seen.add(rp)
                    result.append(rp)

        elif p.is_dir():
            for f in p.rglob("*"):
                if "_banner_ratio_fixed" in f.parts:
                    continue

                if f.is_file() and f.suffix.lower() in SUPPORTED:
                    rp = f.resolve()
                    if rp not in seen:
                        seen.add(rp)
                        result.append(rp)

    return sorted(result)


def resize_keep_ratio_no_crop(im: Image.Image):
    """
    600x166 범위 안에 원본 전체가 들어오도록 비율 유지 축소.
    캔버스/여백/크롭 없음.
    작은 이미지는 확대하지 않음.
    """
    rgba = im.convert("RGBA")
    src_w, src_h = rgba.size

    scale_w = MAX_W / src_w
    scale_h = MAX_H / src_h

    # 더 많이 줄여야 하는 쪽 기준
    scale = min(scale_w, scale_h, 1.0)

    # 이미 범위 안이면 그대로
    if scale >= 1.0:
        return rgba.copy(), False, 1.0

    new_w = max(1, int(round(src_w * scale)))
    new_h = max(1, int(round(src_h * scale)))

    resized = rgba.resize(
        (new_w, new_h),
        Image.Resampling.LANCZOS
    )

    return resized, True, scale


def convert_one(src: Path):
    with Image.open(src) as im:
        before_mode = im.mode
        before_size = im.size

        result, was_resized, scale = resize_keep_ratio_no_crop(im)

        out_dir = src.parent / "_banner_ratio_fixed"
        out_dir.mkdir(parents=True, exist_ok=True)

        dst = out_dir / f"{src.stem}.png"

        # RGBA truecolor PNG
        result.save(dst, format="PNG", optimize=True)

        return {
            "src": src,
            "dst": dst,
            "before_mode": before_mode,
            "before_size": before_size,
            "after_size": result.size,
            "was_resized": was_resized,
            "scale": scale,
        }


def choose_paths():
    root = tk.Tk()
    root.withdraw()

    folder_mode = messagebox.askyesno(
        "배너 비율 축소 + RGBA Fix",
        "폴더 전체를 처리할까요?\n\n"
        "예 : 폴더 지정\n"
        "아니오 : 이미지 파일 지정"
    )

    if folder_mode:
        selected = filedialog.askdirectory(
            title="이미지가 들어있는 폴더 선택"
        )
        paths = [selected] if selected else []
    else:
        selected = filedialog.askopenfilenames(
            title="변환할 이미지 선택",
            filetypes=[
                ("이미지", "*.png;*.jpg;*.jpeg;*.webp"),
                ("PNG", "*.png"),
                ("JPG", "*.jpg;*.jpeg"),
                ("WEBP", "*.webp"),
            ]
        )
        paths = list(selected)

    root.destroy()
    return paths


def main():
    paths = sys.argv[1:]

    if not paths:
        paths = choose_paths()

    files = gather_images(paths)

    if not files:
        print("처리할 이미지가 없습니다.")
        try:
            root = tk.Tk()
            root.withdraw()
            messagebox.showwarning(
                "배너 비율 축소",
                "처리할 이미지가 없습니다."
            )
            root.destroy()
        except Exception:
            pass
        return

    print("=" * 80)
    print("배너 비율 축소 시작")
    print(f"최대 크기 : {MAX_W} x {MAX_H}")
    print("크롭      : 없음")
    print("강제여백  : 없음")
    print("찌그러짐  : 없음")
    print("비율      : 원본 유지")
    print("작은이미지: 확대 안 함")
    print("PNG       : RGBA truecolor")
    print("=" * 80)

    ok = 0
    fail = 0

    for src in files:
        try:
            r = convert_one(src)
            ok += 1

            bw, bh = r["before_size"]
            aw, ah = r["after_size"]

            print(
                f"[완료] {src.name}\n"
                f"       원본 : {bw}x{bh} / {r['before_mode']}\n"
                f"       결과 : {aw}x{ah}\n"
                f"       배율 : {r['scale']:.6f}\n"
                f"       처리 : {'축소' if r['was_resized'] else '크기 유지'}\n"
                f"       저장 : {r['dst']}"
            )

        except Exception as e:
            fail += 1
            print(f"[실패] {src.name} : {e}")

    print("-" * 80)
    print(f"완료: {ok}개 / 실패: {fail}개")

    try:
        root = tk.Tk()
        root.withdraw()
        messagebox.showinfo(
            "배너 비율 축소 완료",
            f"완료: {ok}개\n"
            f"실패: {fail}개\n\n"
            f"최대 범위: {MAX_W}x{MAX_H}\n"
            "원본 비율 유지\n"
            "크롭 없음\n"
            "강제 여백 없음\n"
            "작은 이미지는 확대하지 않음\n"
            "RGBA Fix 적용"
        )
        root.destroy()
    except Exception:
        pass


if __name__ == "__main__":
    main()
