#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
pptx2pdf.py

PowerPoint ファイル (.ppt/.pptx) を PDF に変換する小モジュール。

特徴:
- Windows + Microsoft PowerPoint + comtypes を使用
- モジュールとして import して pptx_to_pdf() を再利用可能
- Launcher から直接実行したときにエラー画面がすぐ閉じないよう、
  import 失敗時・CLI 実行終了時には input() で一時停止する

使用例:
    python pptx2pdf.py input.pptx
    python pptx2pdf.py input.pptx output.pdf
    python pptx2pdf.py input.pptx --overwrite 1 --quiet 0

モジュール利用例:
    from pptx2pdf import pptx_to_pdf

    pdf = pptx_to_pdf("lecture.pptx", overwrite=True, quiet=False)
    if pdf is None:
        print("PDF変換に失敗しました")
"""

from __future__ import annotations

import argparse
import os
import sys
from pathlib import Path
from typing import Iterable


try:
    import comtypes.client
except Exception as e:
    # Launcher から起動したときにエラー画面が一瞬で閉じるのを防ぐため、
    # ここはユーザー希望により input() を残す。
    print("\npptx2pdf.py: Import error: comtypes.client", file=sys.stderr)
    print("Install: pip install comtypes", file=sys.stderr)
    print(f"Original error: {e}", file=sys.stderr)
    input("\nPress ENTER to terminate>>\n")
    raise


POWERPOINT_FORMAT_PDF = 32


def _log(message: str, quiet: bool = False) -> None:
    if not quiet:
        print(message)


def _normalize_path(path: str | os.PathLike) -> str:
    return str(Path(path).expanduser().resolve())


def pptx_to_pdf(
    input_path: str | os.PathLike,
    output_path: str | os.PathLike | None = None,
    *,
    overwrite: bool = True,
    quiet: bool = False,
    visible: bool = True,
) -> str | None:
    """
    PowerPointファイルをPDFに変換します。

    Parameters
    ----------
    input_path:
        入力 PowerPoint ファイル (.ppt/.pptx)。
    output_path:
        出力 PDF ファイル。None の場合は入力ファイルと同じ場所・同じstemで .pdf。
    overwrite:
        True の場合、既存 PDF を上書きします。
        False の場合、出力先が存在すれば変換せず None を返します。
    quiet:
        True の場合、進行メッセージを抑制します。
    visible:
        True の場合、PowerPointアプリケーションを表示します。
        PowerPoint/COMの都合で、環境によっては False 相当が不安定な場合があります。

    Returns
    -------
    str | None
        成功時は出力PDFの絶対パス、失敗時は None。
    """
    input_abs = _normalize_path(input_path)

    if output_path is None:
        output_abs = str(Path(input_abs).with_suffix(".pdf"))
    else:
        output_abs = _normalize_path(output_path)

    input_file = Path(input_abs)
    output_file = Path(output_abs)

    if not input_file.is_file():
        _log(f"  Error: input file not found: '{input_abs}'", quiet)
        return None

    if input_file.suffix.lower() not in (".ppt", ".pptx"):
        _log(f"  Warning: input file extension is not .ppt/.pptx: '{input_abs}'", quiet)

    if output_file.exists():
        if overwrite:
            try:
                output_file.unlink()
                _log(f"  Existing PDF removed: '{output_abs}'", quiet)
            except Exception as e:
                _log(f"  Error: cannot overwrite existing PDF '{output_abs}': {e}", quiet)
                return None
        else:
            _log(f"  Error: output file already exists: '{output_abs}'", quiet)
            return None

    output_file.parent.mkdir(parents=True, exist_ok=True)

    _log(f"  Attempting to open PowerPoint file: '{input_abs}'", quiet)

    powerpoint = None
    presentation = None

    try:
        powerpoint = comtypes.client.CreateObject("PowerPoint.Application")
        powerpoint.Visible = 1 if visible else 0

        presentation = powerpoint.Presentations.Open(input_abs, WithWindow=False)
        presentation.SaveAs(output_abs, POWERPOINT_FORMAT_PDF)
        presentation.Close()
        presentation = None

        _log(f"  Successfully converted to PDF: '{output_abs}'", quiet)
        return output_abs

    except Exception as e:
        _log(f"  Error converting '{input_abs}' to PDF: {e}", quiet)

        if presentation is not None:
            try:
                presentation.Close()
            except Exception:
                pass

        return None

    finally:
        if powerpoint is not None:
            try:
                powerpoint.Quit()
            except Exception:
                pass


def convert_many(
    input_paths: Iterable[str | os.PathLike],
    output_dir: str | os.PathLike | None = None,
    *,
    overwrite: bool = True,
    quiet: bool = False,
    visible: bool = True,
) -> list[str]:
    """
    複数のPowerPointファイルをPDFに変換します。

    Parameters
    ----------
    input_paths:
        入力 PowerPoint ファイルのリスト。
    output_dir:
        出力先ディレクトリ。None の場合は各入力ファイルと同じ場所。
    overwrite, quiet, visible:
        pptx_to_pdf() と同じ。

    Returns
    -------
    list[str]
        変換に成功したPDFパスのリスト。
    """
    converted: list[str] = []

    for input_path in input_paths:
        input_abs = Path(_normalize_path(input_path))

        if output_dir is None:
            output_path = input_abs.with_suffix(".pdf")
        else:
            output_path = Path(output_dir).expanduser().resolve() / f"{input_abs.stem}.pdf"

        pdf = pptx_to_pdf(
            input_abs,
            output_path,
            overwrite=overwrite,
            quiet=quiet,
            visible=visible,
        )

        if pdf is not None:
            converted.append(pdf)

    return converted


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="PowerPointファイル(.ppt/.pptx)をPDFに変換します。",
        formatter_class=argparse.RawTextHelpFormatter,
    )

    parser.add_argument(
        "input",
        nargs="?",
        help="入力 PowerPoint ファイル (.ppt/.pptx)",
    )
    parser.add_argument(
        "output",
        nargs="?",
        help="出力 PDF ファイル。省略時は入力ファイルと同名 .pdf",
    )
    parser.add_argument(
        "--overwrite",
        type=int,
        default=1,
        choices=[0, 1],
        help="既存PDFを上書きするか。1:上書き, 0:上書きしない (default: 1)",
    )
    parser.add_argument(
        "--quiet",
        type=int,
        default=0,
        choices=[0, 1],
        help="進行メッセージを抑制するか。1:抑制, 0:表示 (default: 0)",
    )
    parser.add_argument(
        "--visible",
        type=int,
        default=1,
        choices=[0, 1],
        help="PowerPointを表示するか。1:表示, 0:非表示 (default: 1)",
    )
    parser.add_argument(
        "--pause",
        type=int,
        default=1,
        choices=[0, 1],
        help="終了時にENTER待ちするか。Launcher用に default: 1",
    )

    return parser.parse_args()


def main() -> int:
    args = parse_args()

    if not args.input:
        print("Usage: python pptx2pdf.py input.pptx [output.pdf]")
        if args.pause:
            input("\nPress ENTER to terminate>>\n")
        return 1

    pdf = pptx_to_pdf(
        args.input,
        args.output,
        overwrite=bool(args.overwrite),
        quiet=bool(args.quiet),
        visible=bool(args.visible),
    )

    if pdf is None:
        print("\nPDF conversion failed.", file=sys.stderr)
        if args.pause:
            input("\nPress ENTER to terminate>>\n")
        return 1

    print("\nProgram execution completed.")

    if args.pause:
        input("\nPress ENTER to terminate>>\n")

    return 0


if __name__ == "__main__":
    raise SystemExit(main())
