#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
pandoc.py : Pandocユーティリティ（テンプレート生成 + 多方向変換）
- --convert は出力ファイル名/テンプレート拡張子から推定可能な場合は省略可
- 例:
    # テンプレート生成（拡張子から自動推定）
    python pandoc.py --make_template --template template_textbook.docx
    python pandoc.py --make_template --template template_slide.pptx

    # 変換（拡張子から自動推定）
    python pandoc.py --infile lecture_textbook.md --outfile lecture_textbook.docx --template template_textbook.docx
    python pandoc.py --infile lecture_slide.md    --outfile lecture_slide.pptx    --template template_slide.pptx
    python pandoc.py --infile page.md --outfile page.html --standalone
    python pandoc.py --infile page.md --outfile page.html --mathjax-wrap
    python pandoc.py --infile page.html --outfile page.md

    # 明示的に指定したい場合
    python pandoc.py --convert html --infile a.md --outfile a.html
"""

import sys
import argparse
import subprocess
from pathlib import Path
import re

# -------------------------
# 拡張子 → Pandoc フォーマット
# -------------------------
EXT_TO_FMT = {
    # 入力/出力双方で使い回す（Pandocが理解する代表的キーへ正規化）
    'md': 'markdown',
    'markdown': 'markdown',
    'mkd': 'markdown',
    'mkdn': 'markdown',
    'mdown': 'markdown',
    'rmd': 'markdown',
    'html': 'html',
    'htm': 'html',
    'docx': 'docx',
    'pptx': 'pptx',
    'tex': 'latex',
    'pdf': 'pdf',
    'epub': 'epub',
    'org': 'org',
    'rst': 'rst',
    'ipynb': 'ipynb',
}

def infer_fmt_from_path(path: str | None) -> str | None:
    if not path:
        return None
    ext = Path(path).suffix.lower().lstrip('.')
    return EXT_TO_FMT.get(ext)

def run_command(cmd: list) -> bool:
    print(f"⚡️ 実行中: {' '.join(cmd)}")
    try:
        _ = subprocess.run(cmd, check=True, capture_output=True, text=True, encoding='utf-8')
        print("✅ コマンドは正常に完了しました。")
        return True
    except FileNotFoundError:
        print(f"❌ '{cmd[0]}' が見つかりません。Pandoc はインストール済みで PATH が通っていますか？", file=sys.stderr)
    except subprocess.CalledProcessError as e:
        print(f"❌ Pandoc 実行エラー (終了コード: {e.returncode})", file=sys.stderr)
        print(f"--- stderr ---\n{e.stderr}\n--------------", file=sys.stderr)
    return False

# -------------------------
# テンプレート生成
# -------------------------
def make_pandoc_template(pandoc_path: str, template_file: str):
    target = infer_fmt_from_path(template_file)
    if target not in ('docx', 'pptx'):
        print("❌ --make_template は .docx か .pptx のテンプレート名を指定してください。", file=sys.stderr)
        sys.exit(1)

    print(f"🎨 {target.upper()} 用の Pandoc テンプレートを作成します...")
    data_file = 'reference.docx' if target == 'docx' else 'reference.pptx'
    cmd = [pandoc_path, '-o', template_file, f'--print-default-data-file={data_file}']
    if run_command(cmd):
        print(f"📄 テンプレート '{template_file}' を作成しました。編集してスタイルを調整してください。")

# -------------------------
# 変換
# -------------------------
def convert_with_pandoc(
    pandoc_path: str,
    infile: str,
    outfile: str | None,
    convert: str | None,
    template: str | None,
    in_from: str | None,
    css: str | None,
    no_yaml: bool,
    standalone: bool,
    mathjax_wrap: bool,
    extra_args: list[str]
):
    if not Path(infile).exists():
        print(f"❌ 入力 '{infile}' が存在しません。", file=sys.stderr)
        sys.exit(1)

    # 入力/出力/変換先フォーマットを推定
    src_fmt = in_from or infer_fmt_from_path(infile)

    # outfile がなければ、convert から決める（なければエラー）
    if not outfile:
        if convert:
            outfile = str(Path(infile).with_suffix('.' + convert))
        elif template:
            # テンプレート拡張子から推定（docx/pptx限定）
            t_fmt = infer_fmt_from_path(template)
            if t_fmt in ('docx', 'pptx'):
                outfile = str(Path(infile).with_suffix('.' + t_fmt))
                convert = t_fmt
            else:
                print("❌ 変換先が推定できません。--outfile か --convert を指定してください。", file=sys.stderr)
                sys.exit(1)
        else:
            print("❌ 変換先が推定できません。--outfile か --convert を指定してください。", file=sys.stderr)
            sys.exit(1)

    # 変換先フォーマット
    dst_fmt = convert or infer_fmt_from_path(outfile) or infer_fmt_from_path(template)
    if not dst_fmt:
        print("❌ 変換先フォーマットが推定できません。--convert か --outfile を見直してください。", file=sys.stderr)
        sys.exit(1)

    # Pandoc コマンド組み立て
    cmd = [pandoc_path, infile, '-o', outfile]

    # 入力の -f
    if no_yaml and (src_fmt in (None, 'markdown')):
        cmd.extend(['-f', 'markdown-yaml_metadata_block'])
    elif src_fmt:
        cmd.extend(['-f', src_fmt])

    # 出力の -t
    cmd.extend(['-t', dst_fmt])

    # HTML 独自オプション
    if dst_fmt == 'html':
        if css:
            cmd.extend(['--css', css])
        if standalone and not mathjax_wrap:
            cmd.append('-s')  # 通常のスタンドアロンHTML
        # mathjax_wrap の場合は断片を生成したいので -s は付けない

    # テンプレート（docx/pptx時に推奨）
    if dst_fmt in ('docx', 'pptx'):
        if template:
            cmd.extend(['--reference-doc', template])
        elif template is None:
            # テンプレ未指定でもPandocは生成できるが、明示的に注意喚起
            print("ℹ️ --template（reference-doc）未指定：既定スタイルで出力します。")

    # 追加の生引数（将来拡張用）
    if extra_args:
        cmd.extend(extra_args)

    # 実行
    if not run_command(cmd):
        sys.exit(1)

    # -------------------------
    # MathJaxラップ（HTMLのみ）
    # -------------------------
    if dst_fmt == 'html' and mathjax_wrap:
        try:
            # Pandoc の出力（ボディ断片）を読み込み
            with open(outfile, 'r', encoding='utf-8') as f:
                body_content = f.read()

            # 既に<html>などが混ざっていた場合は、body だけを抽出してみる
            # （断片ではなくスタンドアロンが出てしまった場合の保険）
            # 単純正規表現で <body>…</body> を抜く
            m = re.search(r"<body[^>]*>([\s\S]*?)</body>", body_content, re.IGNORECASE)
            if m:
                body_content = m.group(1)

            # ご提示のテンプレートでラップ
            html_template = f"""<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
  <script id="MathJax-script" async
    src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/mml-chtml.js"></script>
</head>
<body>
{body_content}
</body>
</html>
"""
            with open(outfile, 'w', encoding='utf-8') as f:
                f.write(html_template)
            print(f"🧮 MathJax ラップ済みHTMLを書き出しました: {outfile}")
        except Exception as e:
            print(f"⚠️ MathJax ラップで例外が発生しました: {e}", file=sys.stderr)

def parse_args():
    p = argparse.ArgumentParser(
        description="Pandocユーティリティ（テンプレ生成 & 多方向変換）。--convertは推定できれば省略可。",
        formatter_class=argparse.RawTextHelpFormatter
    )
    p.add_argument('--pandoc_path', default='pandoc', help='pandoc 実行ファイルのパス')
    p.add_argument('--infile', help='入力ファイル')
    p.add_argument('--outfile', help='出力ファイル（拡張子から変換先を推定）')
    p.add_argument('--convert', help='変換先フォーマット（html, markdown, docx, pptx など）')  # オプション化
    p.add_argument('--from', dest='in_from', help='入力フォーマットを明示指定（省略時は拡張子から推定）')
    p.add_argument('--template', help='--reference-doc に渡すテンプレート（.docx/.pptx 推奨）')
    p.add_argument('--css', help='HTML 変換時に適用する CSS')
    p.add_argument('--no-yaml', action='store_true', help='入力を markdown-yaml_metadata_block として解釈')
    p.add_argument('--standalone', action='store_true', help='HTML 出力をスタンドアロンに（<html>〜 をPandocで生成）')
    p.add_argument('--mathjax-wrap', action='store_true', help='HTML 出力（断片）をMathJax対応テンプレートで包む')
    p.add_argument('--extra', nargs=argparse.REMAINDER, help='Pandocへそのまま渡す追加引数（先頭の--は不要）')

    # テンプレ生成
    p.add_argument('--make_template', action='store_true', help='--template で指定した拡張子から形式を推定してテンプレートを生成して終了')

    p.add_argument('--pause', action='store_true', help='終了前に入力待ち')
    return p, p.parse_args()

def main():
    parser, args = parse_args()

    # テンプレ生成（最優先）
    if args.make_template:
        if not args.template:
            parser.error("--make_template を使うには --template を指定してください（.docx か .pptx）")
        make_pandoc_template(args.pandoc_path, args.template)
        if args.pause:
            input("\nPress ENTER to exit >>\n")
        return

    # 変換
    if not args.infile:
        parser.print_help()
        print("\n❗ 変換には --infile が必要です。")
        return

    convert_with_pandoc(
        pandoc_path=args.pandoc_path,
        infile=args.infile,
        outfile=args.outfile,
        convert=args.convert,
        template=args.template,
        in_from=args.in_from,
        css=args.css,
        no_yaml=args.no_yaml,
        standalone=args.standalone,
        mathjax_wrap=args.mathjax_wrap,
        extra_args=(args.extra or []),
    )

    if args.pause:
        input("\nPress ENTER to exit >>\n")

if __name__ == "__main__":
    main()
