#!/usr/bin/env python3
"""在本地压缩图片/视频，并部署到 nginx-server 的 /usr/local/nginx/html/rental-260630/。

用法：
    python3 deploy_vps.py
"""
import json
import shutil
import subprocess
from pathlib import Path

from PIL import Image

BASE_DIR = Path(__file__).parent.resolve()  # html_logs/
SRC_DIR = BASE_DIR / "租房260630"
STAGING_DIR = BASE_DIR / "vps_staging"
VPS_HOST = "nginx-server@81.70.105.160"
VPS_REMOTE_DIR = "/usr/local/nginx/html/rental-260630"

DIR_TO_SLUG = {
    "万北2-711": "wanquanzhuangbei-2-711",
    "万北4-310": "wanquanzhuangbei-4-310",
    "小南庄24": "xiaonanzhuang-24-762",
    "红5楼": "lixinhong-5-1-6",
    "三义庙": "sanyimiao-1ceng",
    "财智公馆G": "caizhihuiguan-G",
    "财智公馆3": "caizhihuiguan-3",
}

IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif"}
VIDEO_EXTS = {".mp4", ".mov", ".webm", ".mkv"}

# 压缩参数
FULL_MAX_SIZE = 1600      # 大图最长边
FULL_QUALITY = 80         # JPEG 质量
THUMB_MAX_SIZE = 480      # 缩略图最长边
THUMB_QUALITY = 75        # 缩略图质量
VIDEO_MAX_WIDTH = 1280    # 视频最大宽度
VIDEO_CRF = 28            # H.264 质量（越小越好，越大越小）


def compress_image(src: Path, dst: Path) -> bool:
    """压缩图片，限制最长边并保存为 JPEG。"""
    try:
        dst.parent.mkdir(parents=True, exist_ok=True)
        with Image.open(src) as im:
            if im.mode in ("RGBA", "P"):
                im = im.convert("RGB")
            # 等比缩放，最长边不超过 FULL_MAX_SIZE
            im.thumbnail((FULL_MAX_SIZE, FULL_MAX_SIZE), Image.LANCZOS)
            im.save(dst, "JPEG", quality=FULL_QUALITY, optimize=True)
        return True
    except Exception as e:
        print(f"  [图片压缩失败] {src}: {e}")
        return False


def make_thumbnail(src: Path, dst: Path) -> bool:
    """生成缩略图。"""
    try:
        dst.parent.mkdir(parents=True, exist_ok=True)
        with Image.open(src) as im:
            if im.mode in ("RGBA", "P"):
                im = im.convert("RGB")
            im.thumbnail((THUMB_MAX_SIZE, THUMB_MAX_SIZE), Image.LANCZOS)
            im.save(dst, "JPEG", quality=THUMB_QUALITY, optimize=True)
        return True
    except Exception as e:
        print(f"  [缩略图失败] {src}: {e}")
        return False


def compress_video(src: Path, dst: Path) -> bool:
    """用 ffmpeg 压缩视频。"""
    dst.parent.mkdir(parents=True, exist_ok=True)
    cmd = [
        "ffmpeg", "-y", "-i", str(src),
        "-c:v", "libx264",
        "-crf", str(VIDEO_CRF),
        "-preset", "medium",
        "-vf", f"scale='min({VIDEO_MAX_WIDTH},iw)':-2,format=yuv420p",
        "-c:a", "aac",
        "-b:a", "128k",
        "-movflags", "+faststart",
        str(dst),
    ]
    try:
        subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    except subprocess.CalledProcessError as e:
        print(f"  [视频压缩失败] {src}: {e}")
        return False


def stage():
    """在本地生成压缩后的网页和媒体文件。"""
    print(f"准备本地 staging 目录: {STAGING_DIR}")
    if STAGING_DIR.exists():
        shutil.rmtree(STAGING_DIR)
    STAGING_DIR.mkdir(parents=True)

    # 为每个 slug 创建目录
    for slug in DIR_TO_SLUG.values():
        (STAGING_DIR / "media" / slug / "thumbs").mkdir(parents=True, exist_ok=True)

    data = {slug: {"images": [], "thumbnails": [], "videos": []} for slug in DIR_TO_SLUG.values()}

    for src_name, slug in DIR_TO_SLUG.items():
        src_dir = SRC_DIR / src_name
        if not src_dir.exists():
            print(f"警告：源目录不存在 {src_dir}")
            continue

        print(f"处理 {src_name} -> {slug}")
        for f in sorted(src_dir.iterdir()):
            if not f.is_file():
                continue
            # 跳过已生成的 thumbs
            if f.parent.name == "thumbs":
                continue

            ext = f.suffix.lower()
            if ext in IMAGE_EXTS:
                out_name = f.stem + ".jpg"
                full_path = STAGING_DIR / "media" / slug / out_name
                thumb_path = STAGING_DIR / "media" / slug / "thumbs" / out_name

                if compress_image(f, full_path):
                    data[slug]["images"].append(f"media/{slug}/{out_name}")
                if make_thumbnail(f, thumb_path):
                    data[slug]["thumbnails"].append(f"media/{slug}/thumbs/{out_name}")

            elif ext in VIDEO_EXTS:
                out_name = f.stem + ".mp4"
                out_path = STAGING_DIR / "media" / slug / out_name
                if compress_video(f, out_path):
                    data[slug]["videos"].append(f"media/{slug}/{out_name}")

    # 写入 media.json
    with open(STAGING_DIR / "media.json", "w", encoding="utf-8") as fp:
        json.dump(data, fp, ensure_ascii=False, indent=2)
    print(f"已生成 {STAGING_DIR / 'media.json'}")

    # 复制 comps.html
    shutil.copy(BASE_DIR / "comps.html", STAGING_DIR / "comps.html")
    print(f"已复制 comps.html")

    # 统计
    total_img = sum(len(v["images"]) for v in data.values())
    total_vid = sum(len(v["videos"]) for v in data.values())
    print(f"媒体统计: {total_img} 张图, {total_vid} 个视频")


def upload():
    """用 rsync 上传到 VPS。"""
    print(f"\n上传到 {VPS_HOST}:{VPS_REMOTE_DIR}")
    cmd = [
        "rsync", "-avz", "--delete",
        str(STAGING_DIR) + "/",
        f"{VPS_HOST}:{VPS_REMOTE_DIR}/",
    ]
    subprocess.run(cmd, check=True)
    print("上传完成")


if __name__ == "__main__":
    stage()
    upload()
    print(f"\n页面地址: https://www.drail-2023.asia/rental-260630/comps.html")
