#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import argparse
import shutil
from glob import glob
import subprocess
import traceback
from pathlib import Path
from datetime import datetime


SCRIPT_FULLPATH = os.path.abspath(sys.argv[0])
SCRIPT_DIR = os.path.dirname(SCRIPT_FULLPATH)
SCRIPT_BASENAME = os.path.splitext(os.path.basename(SCRIPT_FULLPATH))[0]

# 起動スクリプトのディレクトリに基づいたパス設定
ADD_DOCSTRING_PATH = os.path.join(SCRIPT_DIR, "add_docstring.py")
EXPLAIN_PROGRAM_PATH = os.path.join(SCRIPT_DIR, "explain_program5.py")
DEFAULT_INI_PATH = os.path.join(SCRIPT_DIR, f"{SCRIPT_BASENAME}.ini")


def relative_from_source(argv0: str) -> str:
    p = Path(argv0).resolve()
    parts = p.parts

    # 最初に出現する "source" を探す
    try:
        idx = parts.index("source")
    except ValueError:
#        raise RuntimeError("'source' ディレクトリがパスに含まれていません")
        return ""

    # source 以下のパス（ファイル名付き）
    rel_path = Path(*parts[idx+1:])

    # ファイル名を削除してディレクトリだけにする
    return str(rel_path.parent)


def run_step(message, cmd_list):
    """作業ステップを表示し、外部コマンドを実行します。"""
    print(f"\n>>> {message}")
    print(f"    コマンド: {' '.join(cmd_list)}")
    try:
        result = subprocess.run(cmd_list, text=True, errors='ignore')
#        result = subprocess.run(cmd_list, capture_output=True, text=True, encoding='utf-8', errors='ignore')
        if result.returncode != 0:
            print(f"!!! エラーが発生しました:\n{result.stderr}")
            return False
        return True
    except Exception as e:
        print(f"!!! 実行エラー: {e}")
        return False

def make_init_py(path):
    if os.path.exists(path):
        print(f">>> Step: {path} が見つかりました。")
    else:
        print(f">>> Step: {path} を作成中...")
        with open(path, "w", encoding="utf-8") as f:
            f.write("")
        print(f"    Done: {path}")


def make_index_template(path, module_path):
    if os.path.exists(path):
        print(f">>> Step: {path} に追加中...")
        with open(path, "a", encoding="utf-8") as f:
            f.write(f"   {module_path}_index\n")
        print(f"    Done: {path}")
    else:
        print(f">>> Step: {path} を作成中...")
        content = f"""\
プロジェクト全体ドキュメント
============================

.. toctree::
   :maxdepth: 2
   :caption: メインメニュー:
   :hidden:
   :glob:

   {module_path}_index
"""
        with open(path, "w", encoding="utf-8") as f:
            f.write(content)
        print(f"    Done: {path}")

def make_index_rst(index_rst, base_name, package_path):
    print(f">>> Step: {index_rst} を作成中...")
    index_content = f"""{base_name} ドキュメント
============================================================================

.. toctree::
   :maxdepth: 1

   {base_name}_usage
   {base_name}_examples
   {base_name}_api
"""
    with open(index_rst, "w", encoding="utf-8") as f:
        f.write(index_content)
    print(f"    Done: {index_rst}")

def make_api_rst(api_rst, base_name, package_path):
    print(f">>> Step: {api_rst} を作成中...")
    api_content = f"""{base_name} プログラム仕様
============================================================================

.. currentmodule:: {package_path}

.. automodule:: {package_path}
   :members:
   :undoc-members:
   :show-inheritance:
"""
    with open(api_rst, "w", encoding="utf-8") as f:
        f.write(api_content)
    print(f"    Done: {api_rst}")

def make_examples_md(examples_md, infile, base_name):
    print(f">>> Step: {examples_md} テンプレートを作成中...")

# 画像ファイルの自動検出
    image_files = sorted(
        f for f in os.listdir(".")
        if f.startswith(base_name) and f.lower().endswith((".png", ".jpg", ".jpeg"))
        )

# データファイルの自動検出（CSV / Excel / TXT）
    data_files = sorted(
        f for f in os.listdir(".")
        if f.startswith(base_name) and f.lower().endswith((".csv", ".xlsx", ".xls", ".txt"))
        )
    
    print("Image files:", image_files)
    print("Data files:", data_files)

    
    # ヘルプ出力を取得
    print("  help logを取得します")
    result = subprocess.run(["python", infile, "--help"], 
                   text=True, capture_output = True)
    print("    return code:", result.returncode)
    if result.returncode == 0:
        help_log = result.stdout + "\n" + result.stderr
#        print("    help log:", help_log)                        
    else:
        help_log = "(ヘルプの自動取得に失敗しました。ここに実行ログを貼り付けてください)"

    if data_files:
        data_section = "## データファイル\n"
        for df in data_files:
            data_section += f"- [{df}](./{df})\n"
        data_section += "\n"
    else:
        data_section = "## 生成されたデータファイル\n（データファイルが見つかりませんでした）\n\n"

    if image_files:
        image_section = "## 画像ファイル\n\n"
        for img in image_files:
            image_section += f"- [{img}](./{img})\n"
            image_section += f"![{img}](./{img})\n\n"
    else:
        image_section = "## 生成された画像一覧\n（画像ファイルが見つかりませんでした）\n\n"


    examples_content = f"""# {base_name} 実行例

## help出力 `{base_name}.py --help`

<pre style="background-color: #f4f4f4; border: 1px solid #ccc; padding: 10px; border-radius: 5px; font-family: 'Courier New', Courier, monospace; overflow-x: auto;">
{help_log}
</pre>

{data_section}

{image_section}

"""

    with open(examples_md, "w", encoding="utf-8") as f:
        f.write(examples_content)
    print(f"    Done: {examples_md}")


def main(args):
    infile = args.infile
    if not os.path.exists(infile):
        print(f"エラー: 入力ファイル '{infile}' が見つかりません。")
        return

    # 基本情報の整理
    base_name = os.path.splitext(os.path.basename(infile))[0]
    date_str = datetime.now().strftime("%Y%m%d")
    
    # ファイル名定義
    init_py = "__init__.py"
    index_template = "index.template"
    docstring_out = f"{base_name}_docstring.py"
    backup_file = f"{base_name}_{date_str}.py"
    usage_md = f"{base_name}_usage.md"
    examples_md = f"{base_name}_examples.md"
    index_rst = f"{base_name}_index.rst"
    api_rst = f"{base_name}_api.rst"

    # カレントディレクトリ名からパッケージパスを判定 (010...等の数値ディレクトリを想定)
    current_dir_name = os.path.basename(os.getcwd())
    # フォルダ名が 010xx_page のような形式ならモジュールパスに含める
#    module_path = f"{current_dir_name}.{base_name}" if "page" in current_dir_name else base_name
    if args.subdir is not None and args.subdir != "":
        module_path = os.path.join(args.subdir, base_name)
        package_path = f"{args.subdir}.{base_name}"
    else:
        package_path = module_path
        module_path = base_name

    print("="*60)
    print(f" プロジェクト: {base_name} のSphinxファイル自動生成を開始します")
    print(f"    モジュールパス: {module_path}")
    print(f"    パッケージパス: {package_path}")
    print("="*60)

    make_init_py(init_py)
    if os.path.exists(index_template):
        print(f"** Warning: [{index_template}] exists. Skip to create.")
    else:
        make_index_template(index_template, module_path)
    if os.path.exists(index_rst):
        print(f"** Warning: [{index_rst}] exists. Skip to create.")
    else:
        make_index_rst(index_rst, base_name, package_path)
    if os.path.exists(api_rst):
        print(f"** Warning: [{api_rst}] exists. Skip to create.")
    else:
        make_api_rst(api_rst, base_name, package_path)
    if os.path.exists(examples_md):
        print(f"** Warning: [{examples_md}] exists. Skip to create.")
    else:
        make_examples_md(examples_md, infile, base_name)

    args_list = ["--api", args.api, "--update", str(args.update), "--overwrite", str(args.overwrite),
                 "--pause", str(args.pause)]

    # explain_program.py の実行
    if not run_step("Step: EXPLAIN_PROGRAM_PATH を実行してプログラム解説を生成中...", 
                    ["python", EXPLAIN_PROGRAM_PATH, infile, *args_list]):
        return

    # add_docstring.py の実行
    if not run_step("Step: ADD_DOCSTRING_PATH を実行してDocstringを追加中...", 
                    ["python", ADD_DOCSTRING_PATH, infile, *args_list]):
        return

#======================================================================
    # バックアップの作成
    print(f">>> Step: オリジナルファイルのバックアップを作成中...")
    if os.path.exists(infile):
        shutil.copy2(infile, backup_file)
        print(f"    Done: {infile} -> {backup_file}")
    else:
        print("!!! バックアップ対象のファイルが見つかりません。")
        return

#======================================================================
    # ファイルの置き換え
    print(f">>> Step: 生成されたDocstring版ファイルを {infile} にリネーム中...")
    if os.path.exists(docstring_out):
        os.replace(docstring_out, infile)
        print(f"    Done: {docstring_out} -> {infile}")
        with open(docstring_out, "w") as fp:
            fp.write("")
        print(f"    ダミーの空ファイル {docstring_out} を作りました")
    else:
        print("!!! Docstring版ファイルが生成されていなかったため、リネームをスキップします。")
        return


    print("\n" + "="*60)
    print(" 全ての自動生成プロセスが正常に終了しました。")
    print("="*60)


def initialize():
    """コマンドライン引数のパーサーを構築します。"""
    parser = argparse.ArgumentParser(
        description="Sphinxドキュメント生成の一連のルーチン（Docstring追加、バックアップ、解説生成、RST作成）を自動化します。"
    )
    parser.add_argument("infile", help="対象となるPythonスクリプトファイル名 (例: mu_fit.py)")
    parser.add_argument("--subdir", default=None, help="sourceディレクトリからの相対パス")

    parser.add_argument("--api", choices=["openai", "openai5", "google", "gemini"], default='google')
    parser.add_argument("-u", "--update", type=int, default=1)
    parser.add_argument("-w", "--overwrite", type=int, default=0)
    parser.add_argument("-p", "--pause", type=int, default=0)
    return parser


def read_args(parser):
    """引数を解析して返します。"""
    args = parser.parse_args()
    if args.subdir is None:
        args.subdir = relative_from_source(args.infile)

    print()
    print("Args:")
    print(f"  {args.infile=}")
    print(f"  {args.subdir=}")
    print(f"  {args.api=}")
    print(f"  {args.update=}")
    print(f"  {args.overwrite=}")
    print(f"  {args.pause=}")

    return args


if __name__ == "__main__":
    print()
    print(f"=== {sys.argv[0]} ===")
    print(f"{EXPLAIN_PROGRAM_PATH=}")
    print(f"{ADD_DOCSTRING_PATH=}")

    parser = initialize()
    args = read_args(parser)

    try:
        main(args)
    except Exception:
        print("\n" + "!"*60)
        print(" 予期せぬ致命的なエラーが発生しました。")
        traceback.print_exc()
        print("!"*60)
        sys.exit(1)
        