#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import argparse
import glob
import time

from tkai_lib import read_ai_config
from tkai_lib import query_openai4, openai_response_to_json
from tkai_lib import query_openai5, openai5_response_to_json, extract_openai5_text
from tkai_lib import query_google, google_response_to_json



#=========================================================
# Global configuration
#=========================================================
config_path = "ai.env"

#=========================================================
# Read configuration
#=========================================================
read_ai_config(config_path)

max_tokens     = int(os.getenv("max_tokens", "3000"))

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
openai_model   = os.getenv("openai_model", "gpt-4o")
temperature    = float(os.getenv("temperature", "0.3"))

openai_model5  = os.getenv("openai_model5", "gpt-5-nano")
reasoning_effort = os.getenv("reasoning_effort", "low")

GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
google_model   = os.getenv("gemini_model", "gemini-2.5-flash")


#=========================================================
# Parameters
#=========================================================
prompt_templates = {
    "main": (
        "以下は{{language}}言語のプログラム{{script_name}}のコードです。これを解析し、\n"
        "1) プログラムの動作\n"
        "2) 必要な非標準ライブラリとインストールコマンドとインストール方法\n"
        "3) 必要な入力ファイル\n"
        "4) 実行後に生成される出力ファイル\n"
        "5) コマンドラインでの使用例 (Usage)\n"
        "を Markdown 形式で記述してください。\n\n"
        "```{{language}}\n"
        "{{code}}\n"
        "```"
        ),

    "lib": (
        "以下は{{language}}言語のライブラリ{{script_name}}のコードです。これを解析し、\n"
        "1) このライブラリの主な機能や目的\n"
        "2) このライブラリを他のプログラムからimportする方法\n"
        "3) 必要な非標準ライブラリとインストールコマンドとインストール方法\n"
        "4) importできる変数と関数。変数には説明するコメントを、関数には関数の動作と引数・戻り値の説明を入れてください\n"
        "5) main scriptとして実行したときの動作\n"
        "を Markdown 形式で記述してください。\n\n"
        "```{{language}}\n"
        "{{code}}\n"
        "```"
        ),
    }

language_dict = {
    ".py": "python",
    ".pl": "perl",
    ".pm": "perl",
    ".c" : "C",
    ".cpp": "C++",
    ".pas": "pascal",
    ".f"  : "fortran",
    ".for": "fortran",
    ".f77": "fortran",
    ".js" : "Javascript",
    ".java": "Java",
    ".go": "Go",
    ".sh": "bash script",
    ".csh": "tcsh script",
    ".bat": "Windows batch script",
    ".vbs": "Visual Basic script",
    ".css": "Cascade Style Sheet",
    ".html": "HTML",
    ".xml": "XML",
    }


def get_program_type(path):
    base = os.path.basename(path)
    name, ext = os.path.splitext(base)
    if ext == ".pm": return 'lib'
    if base.startswith("tk"): return 'lib'
    return 'main'

def initialize():
    parser = argparse.ArgumentParser(
        description="プログラムコードを読み込み、OpenAI/Google API で使用方法を Markdown に出力するツール"
    )
    parser.add_argument("--api", type=str, default='google',
        choices = ["openai", "openai5", "google", "gemini"],
        help="使用する API を指定（openai5|openai|google|gemini: デフォルト: google）"
    )
    parser.add_argument(
        "pattern",
        help="処理対象ファイルのワイルドカードパターン（例: '*.py'）"
    )
    parser.add_argument(
        "output",
        nargs="?",
        help="出力 Markdown ファイル名。省略した場合は入力ファイルごとに拡張子を .md に置換"
    )
    parser.add_argument(
        "-t", "--program_type",
        choices=["", "main", "lib"],
        default="",
        help="読み込むプログラムのタイプ ['', 'main', 'lib']（デフォルト: ''）"
    )
    parser.add_argument(
        "-u", "--update", type=int, choices=[0, 1], default=0,
        help="出力ファイルが存在し、かつ入力ファイルより古い場合にのみ再生成"
    )
    parser.add_argument(
        "-w", "--overwrite", type=int, choices=[0, 1], default=0,
        help="既存ファイルを問答無用で上書き生成"
    )
    return parser

def get_prompt(inp: str, code: str, program_type: str = ''):
    # 言語判定
    ext = os.path.splitext(inp)[1]
    language = language_dict.get(ext, None)
    if not language:
        print(f"\n{inp}はサポートされていないプログラミング言語です。スキップします")
        return None

    if program_type == '':
        program_type = get_program_type(inp)
    print(f"Program type: {program_type}")

    role = "You are a helpful assistant that generates clear, well-structured documentation for the given program."
    prompt_template = prompt_templates.get(program_type, prompt_templates['main'])
    prompt = (
        prompt_template
        .replace("{{script_name}}", inp)
        .replace("{{code}}", code)
        .replace("{{language}}", language)
    )
    
    return role, prompt

def generate_doc_openai5(inp: str, code: str, program_type: str = '') -> str:
    instructions, prompt = get_prompt(inp, code, program_type)
    response = query_openai5(prompt, openai_model5, openai_api_key = OPENAI_API_KEY, 
                    instructions = instructions, role = None, store = False,
                     effort = reasoning_effort, max_output_tokens = max_tokens)
    if not response: return False
    if response == {}: return {}

    text = extract_openai5_text(response)

    return text

def generate_doc_openai(inp: str, code: str, program_type: str = '') -> str:
    role, prompt = get_prompt(inp, code, program_type)
    response = query_openai4(prompt, openai_model, openai_api_key = OPENAI_API_KEY,
                    role = role, temperature = 0, max_tokens = max_tokens)
    return response.choices[0].message.content

def generate_doc_google(inp: str, code: str, program_type: str = '') -> str:
    role, prompt = get_prompt(inp, code, program_type)
    response = query_google(prompt, google_model, role = role, google_api_key = GOOGLE_API_KEY)
    if not response: return False
    if response == {}: return {}

    return response.text

def main():
    parser = initialize()
    args = parser.parse_args()

    files = glob.glob(args.pattern)
    if not files:
        print(f"Error: パターン '{args.pattern}' にマッチするファイルがありません。", file=sys.stderr)
        sys.exit(1)

    # 出力ファイル名の決定
    if args.output:
        if len(files) > 1:
            print("Error: 複数ファイルを処理するときは output 引数を省略してください。", file=sys.stderr)
            sys.exit(1)
        outputs = [args.output]
    else:
        outputs = [os.path.splitext(f)[0] + ".md" for f in files]

    api = args.api
    print(f"  API: {api.upper()}")
    if 'openai5' in api:
        print(f"  openai_model: {openai_model5}")
        print(f"  effort      : {reasoning_effort}")
        print(f"  max_tokens  : {max_tokens}")
    elif 'openai' in api:
        print(f"  openai_model: {openai_model}")
        print(f"  temperature : {temperature}")
        print(f"  max_tokens  : {max_tokens}")
    else:
        print(f"  google_model: {google_model}")
        print(f"  max_tokens: {max_tokens}")

    print(f"Output files:", outputs)

    print()
    # 各ファイルを処理
    for inp, out in zip(files, outputs):
        do_generate = True
        if os.path.exists(out):
            if args.overwrite:
                do_generate = True
            elif args.update:
                inp_mtime = os.path.getmtime(inp)
                out_mtime = os.path.getmtime(out)
                if out_mtime >= inp_mtime:
                    print(f"[INFO] '{out}' は最新です。スキップします。")
                    do_generate = False
                else:
                    do_generate = True
            else:
                print(f"[INFO] '{out}' が既に存在します。--update または --overwrite を指定して再生成できます。スキップします。")
                do_generate = False
        if not do_generate:
            continue

        print(f"[INFO] Generating doc: {inp} → {out}")
        try:
            code = open(inp, encoding="utf-8").read()
        except:
            try:
                code = open(inp, encoding="shift-jis").read()
            except:
                code = None

        if code is None:
            print(f"\nError: Could not read [{inp}]. Skip.")
            continue
            
        if args.api == "openai5":
            doc = generate_doc_openai5(inp, code, args.program_type)
        elif args.api == "openai":
            doc = generate_doc_openai(inp, code, args.program_type)
        else:
            doc = generate_doc_google(inp, code, args.program_type)

        if doc is None:
            print(f"Error generating doc for {inp}")
            continue

        with open(out, "w", encoding="utf-8") as f:
            f.write(doc)

        # API レート制限回避
        time.sleep(1)

    print("Done.")
    
    input("\nPress ENTER to terminate>>\n")
    

if __name__ == "__main__":
    main()
