import argparse
import json
import os
import platform
import subprocess
from pathlib import Path


def get_ffmpeg_path():
    """FFmpegの実行ファイルのパスを取得する"""
    # デフォルトのFFmpegパス
    if platform.system() == "Windows":
        # Windowsの場合、一般的なインストール場所を確認
        common_paths = [
            r"C:\Program Files\FFmpeg\bin\ffmpeg.exe",
            r"C:\FFmpeg\bin\ffmpeg.exe",
            os.path.join(
                os.getenv("USERPROFILE"), "Downloads", "ffmpeg", "bin", "ffmpeg.exe"
            ),
        ]
        for path in common_paths:
            if os.path.exists(path):
                return path
    return "ffmpeg"  # システムパスに設定されている場合はそのまま'ffmpeg'を返す


def get_ffprobe_path(ffmpeg_path: str = None) -> str:
    """FFprobeの実行ファイルのパスを取得する"""
    if ffmpeg_path:
        # FFmpegのパスからFFprobeのパスを推測
        ffprobe_path = ffmpeg_path.replace("ffmpeg", "ffprobe")
        if os.path.exists(ffprobe_path):
            return ffprobe_path
    return "ffprobe"  # システムパスに設定されている場合


def get_video_duration(input_path: str, ffmpeg_path: str = None) -> float:
    """動画の長さを秒単位で取得"""
    ffprobe_path = get_ffprobe_path(ffmpeg_path)

    # FFprobeの存在確認
    try:
        subprocess.run([ffprobe_path, "-version"], capture_output=True, check=True)
    except (subprocess.SubprocessError, FileNotFoundError):
        raise RuntimeError(
            "FFprobeが見つかりません。FFmpegが正しくインストールされているか確認してください。"
        )

    command = [
        ffprobe_path,
        "-v",
        "error",
        "-show_entries",
        "format=duration",
        "-of",
        "json",
        input_path,
    ]

    try:
        result = subprocess.run(command, capture_output=True, text=True, check=True)
        info = json.loads(result.stdout)
        if "format" not in info or "duration" not in info["format"]:
            raise ValueError("動画の長さ情報が取得できません")
        return float(info["format"]["duration"])
    except subprocess.CalledProcessError as e:
        print(f"FFprobeエラー出力: {e.stderr}")
        raise RuntimeError(f"動画情報の取得に失敗しました: {e.stderr}")
    except json.JSONDecodeError:
        raise RuntimeError("動画情報のJSON解析に失敗しました")


def convert_video_fps(
    input_path: str,
    output_path: str,
    target_fps: int = 30,
    speed: float = 1.0,
    target_duration: float = None,
    ffmpeg_path: str = None,
) -> None:
    """
    動画のフレームレートと再生速度を変換する関数

    Parameters:
        input_path (str): 入力動画のパス
        output_path (str): 出力動画のパス
        target_fps (int): 目標のフレームレート（デフォルト: 30）
        speed (float): 再生速度の倍率（デフォルト: 1.0、1未満で遅く、1より大きいと速く）
        target_duration (float): 目標とする動画の長さ（秒）。指定すると--speedは無視されます
        ffmpeg_path (str): FFmpegの実行ファイルのパス（省略可）
    """
    if not Path(input_path).exists():
        raise FileNotFoundError(f"入力ファイルが見つかりません: {input_path}")

    ffmpeg_cmd = ffmpeg_path if ffmpeg_path else get_ffmpeg_path()

    # 目標時間が指定されている場合、speedを計算
    if target_duration is not None:
        original_duration = get_video_duration(input_path, ffmpeg_cmd)
        speed = original_duration / target_duration
        print(f"元の長さ: {original_duration:.1f}秒")
        print(f"目標時間に合わせた速度: {speed:.2f}倍")

    try:
        # 速度調整用のフィルター設定
        # setptsフィルターで速度を調整（1/speed）
        speed_filter = f"setpts={1/speed}*PTS"

        command = [
            ffmpeg_cmd,
            "-i",
            input_path,
            "-fps_mode",
            "cfr",
            "-filter:v",
            f"{speed_filter},fps={target_fps}",  # 速度調整とFPS変換を連結
            "-c:v",
            "libx264",
            "-preset",
            "medium",
            "-crf",
            "23",
            "-filter:a",
            f"atempo={speed}",  # 音声の速度も調整
            "-y",
            output_path,
        ]

        process = subprocess.run(
            command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
        )

        if process.returncode != 0:
            raise RuntimeError(f"FFmpegエラー: {process.stderr}")

        print(f"変換が完了しました。出力ファイル: {output_path}")
        print(f"設定: FPS={target_fps}, 速度={speed:.2f}倍")

    except Exception as e:
        print(f"エラーが発生しました: {str(e)}")
        raise


def main():
    parser = argparse.ArgumentParser(
        description="動画のフレームレートと再生速度を変換します"
    )
    parser.add_argument("input", help="入力動画のパス")
    parser.add_argument("output", help="出力動画のパス")
    parser.add_argument(
        "--fps", type=int, default=30, help="目標フレームレート（デフォルト: 30）"
    )
    parser.add_argument(
        "--speed",
        type=float,
        default=1.0,
        help="再生速度の倍率（デフォルト: 1.0、1未満で遅く、1より大きいと速く）",
    )
    parser.add_argument(
        "--target-duration",
        type=float,
        help="目標とする動画の長さ（秒）。指定すると--speedは無視されます",
    )
    parser.add_argument("--ffmpeg-path", help="FFmpegの実行ファイルのパス（省略可）")

    args = parser.parse_args()

    try:
        convert_video_fps(
            args.input,
            args.output,
            args.fps,
            args.speed,
            args.target_duration,
            args.ffmpeg_path,
        )
    except Exception as e:
        print(f"プログラムの実行中にエラーが発生しました: {str(e)}")


if __name__ == "__main__":
    main()
