import os
import sys
import argparse
import time
import re
from pathlib import Path
from types import SimpleNamespace
from urllib.parse import urlparse

import chardet
from bs4 import BeautifulSoup
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
import html2text

from pdf2docx import Converter
from docx import Document
from pptx import Presentation
from markitdown import MarkItDown

from tkai_lib import read_ai_config
from tkai_lib import query_openai4, openai_response_to_json
from tkai_lib import query_openai5, extract_openai5_text
from tkai_lib import query_google2, google_response_to_json
from tkai_lib import query_deepl, extract_deepl_text

import openai


#=========================================================
# Global configuration
#=========================================================
role_content = "あなたは専門的な英語を正確かつプロフェッショナルに校正するアシスタントです。"
prompt_template = """\
*#翻訳してほしいテキスト*以降のテキストは学会のプレゼンテーションの一部分です。
以下の条件を守り、良い米国英語に翻訳してください。
条件１：テキストに書かれていない解釈などは追加しない。
条件２：文字数を大きく増やさない。
条件３：動詞が入っていないテキストはスライドページのヘディングなので、完全な文にしない。
{{additional_prompt}}

#翻訳してほしいテキスト\n{{text}}"""

# for reformat
reformat_role = "あなたは専門的な英語を正確かつ筋の通った文章に校正するアシスタントです。"
reformat_prompt = '''\
以下の*＃テキスト*以下の文章はPDFファイルからテキストを抜き出したものですが、段落の順番等が変わっていたりして
文章が壊れています。もとの文章を復元してください 
＃テキスト
{{ text }}'''


parser = None


def initialize():
    cfg = SimpleNamespace()
    cfg.config_path        = "translate5.env"
    cfg.common_config_path = "ai.env"

    read_ai_config(cfg.config_path, read_account_inf = False)
    read_ai_config(cfg.common_config_path)

    parser = argparse.ArgumentParser(description="Translate Configuration Settings")
    
    parser.add_argument("--mode",   default="je", help="Mode of translation")
    parser.add_argument("--infile", default="translate_test.docx", help="Input file for translation")
    parser.add_argument("--output_html_path",   default=None, help="Path for the output HTML file")
    parser.add_argument("--html_template_path", default="template_translate.html", help="Path to the HTML template file")

    parser.add_argument("--api",      default="openai5", choices=["openai5", "openai", "google", "deepl"], help="Translation API to use")
    parser.add_argument("--model",    default=None, help="API model")
    parser.add_argument("--endpoint", default=os.getenv("endpoint"), help="API endpoint")

    parser.add_argument("--max_tokens", type=int, default=int(os.getenv("max_tokens", "2000")), help="Maximum number of tokens")
    parser.add_argument("--openai_api_key",   default=os.getenv("OPENAI_API_KEY"), help="OpenAI API key")
    parser.add_argument("--openai_model",     default=os.getenv("openai_model", "gpt-4o"), help="OpenAI model to use")
    parser.add_argument("--temperature", type=float, default=float(os.getenv("temperature", "0.3")), help="Sampling temperature")
    parser.add_argument("--openai_model5",    default=os.getenv("openai_model5", "gpt-5-nano"), help="OpenAI GPT5 model (gpt-5-nano|gpt-5-mini|gpt-5|gpt-5-chat-latest)")
    parser.add_argument("--reasoning_effort", default=os.getenv("reasoning_effort", "low"), help="Reasoning effort level")
    parser.add_argument("--google_api_key",   default=os.getenv("GOOGLE_API_KEY"), help="Google API key")
    parser.add_argument("--google_model",     default=os.getenv("google_model", "gemini-2.5-flash"), help="Google model to use")
    parser.add_argument("--deepl_api_key",    default=os.getenv("DEEPL_API_KEY"), help="DeepL API Key")

    parser.add_argument("--force_server_charcode", default=os.getenv("force_server_charcode", 'utf-8'), help="force_server_charcode")
    parser.add_argument("--tsleep_rpm", type=float, default=0, help="Sleep time to avoid rpm")

    parser.add_argument("--use_md", action="store_true", help="Use markdown for processing")
    parser.add_argument("--limit_to_multibyte_str", action="store_true", help="Limit processing to multibyte strings")

    parser.add_argument("--process_unit", default="paragraph", choices=["paragraph", "run"], help="Unit of processing")
    parser.add_argument("--min_translate_length",             type=int,   default=int(os.getenv("min_translate_length", "5")), help="Minimum translation length")
    parser.add_argument("--allowed_translation_length_ratio", type=float, default=float(os.getenv("allowed_translation_length_ratio", "5.0")), help="Allowed translation length ratio")

    parser.add_argument("--translate_role",   type=str, default="", help="Role for translation")
    parser.add_argument("--translate_prompt", type=str, default="", help="Prompt for translation")
    parser.add_argument("--reformat_role",    type=str, default="", help="Role for reformat")
    parser.add_argument("--reformat_prompt",  type=str, default="", help="Prompt for reformat")

    return cfg, parser

def update_variables(cfg, parser):
    args = parser.parse_args()

    if args.model is not None:
        if args.api == 'openai5':
            args.openai_model5 = args.model
        elif args.api == 'openai':
            args.openai_model = args.model
        elif args.api == 'google':
            args.google_model = args.model

    if args.translate_role == "":
        args.translate_role = role_content
    if args.translate_prompt == "":
        args.translate_prompt = prompt_template
    if args.reformat_role == "":
        args.reformat_role = reformat_role
    if args.reformat_prompt == "":
        args.reformat_prompt = reformat_prompt

    if args.mode[0] == 'j':
        args.source_lang = "JA"
        args.limit_to_multibyte_str = True
    else:
        args.source_lang = "EN"
        args.limit_to_multibyte_str = False

    if args.mode[1] == 'j':
        args.target_lang = "JA"
    else:
        args.target_lang = "EN"

    return args

def usage():
    parser.print_usage()


# ------------------------------------------------------
# 基本関数
# ------------------------------------------------------
def getarg(i, defval = None):
    if len(sys.argv) > i:
        return sys.argv[i]
    return defval

def process_template(template: str, context: dict) -> str:
    """
    Replace special characters like \t, \n, \r and template tags {{ key }} with their corresponding values.

    Args:
        template (str): The input string containing template tags and special characters.
        context (dict): A dictionary containing key-value pairs for template replacement.

    Returns:
        str: The processed string with replacements applied.
    """
    # Replace special characters
    template = template.replace(r'\t', '\t')
    template = template.replace(r'\n', '\n')
    template = template.replace(r'\r', '\r')
    
    # Replace {{ key }} with context values
    def replace_placeholder(match):
        key = match.group(1).strip()
        return str(context.get(key, f'{{{{ {key} }}}}'))  # Keep original if key not found

    template = re.sub(r'\{\{\s*(.*?)\s*\}\}', replace_placeholder, template)

    return template

# ------------------------------------------------------
# 関数
# ------------------------------------------------------
def save(path, text):
    with open(path, "w", encoding="utf-8") as file:
        file.write(text)

def read_file(path):
    if not os.path.exists(path):
        print("\nError in read_file(): File [{path}] does not exist\n")
        exit()

    fp = open(path, "r", encoding="utf-8")
    if not fp:
        print("\nError in read_file(): Failed to read [{path}]\n")
        exit()
        
    text = fp.read()
    fp.close()
    
    return text

def replace_path(path, ext):
    return os.path.splitext(path)[0] + ext

def check_multibyte_str(text, limit_to_multibyte_str):
    if not limit_to_multibyte_str:
        return True 

    pattern = re.compile(r'[\u0800-\uFFFF]')
    ret = bool(pattern.search(text))

    return ret

def html_to_markdown(html_file_path):
    with open(html_file_path, 'r', encoding='utf-8') as html_file:
        html_content = html_file.read()

    return html2text.html2text(html_content)

def convert_to_md(infile):
    if ".html" in infile.lower(): 
        return html_to_markdown(infile)
    else:
        print()
        print("Convert {infile} to markdown")
#    md = MarkItDown(mlm_client=client, mlm_model="gpt-4o-mini")
        md = MarkItDown()
        result = md.convert(infile)

    return result.text_content

def n_leading_chars(s, c = '#'):
    return len(s) - len(s.lstrip(c))

def pdf_to_docx(pdf_file, docx_file):
    cv = Converter(pdf_file)
    cv.convert(docx_file, start=0, end=None)  # start, endページを指定可能
    cv.close()
    print(f"Converted '{pdf_file}' to '{docx_file}' successfully.")

def get_filetype(path):
    ext = os.path.splitext(path)[1].lower()
    if ext == ".pdf":
        return "pdf"
    elif ext == ".docx":
        return "docx"
    elif ext == ".pptx":
        return "pptx"
    elif ext == ".html" or ext == ".htm":
        return "html"
    elif ext == ".txt" or ext == ".text":
        return "txt"
    elif ext == ".md":
        return "md"

    return None

def to_translate(text, min_translate_length, limit_to_multibyte_str):
    text0 = text.strip()
    if text is None or text0 == '': 
        return False

    if len(text0) < min_translate_length:
        return False

# 2byte文字が含まれるかどうか
    is_mb = check_multibyte_str(text0, limit_to_multibyte_str)
# 2byte文字でなく、アルファベットを含まない場合
    if not is_mb and not bool(re.search('[a-zA-Z]', text0)):
        return False
        
    return is_mb

def revise_with_openai4(text, openai_model, role_content, prompt, temperature, max_tokens, cfg):
#    prompt = f"{prompt}:\n翻訳してほしいテキスト\n{text}"
    prompt = process_template(prompt, { "text": text, "additional_prompt": "" })

    response = query_openai4(prompt, openai_model, role = role_content, 
                             temperature = temperature, max_tokens = max_tokens,
                             openai_api_key = cfg.openai_api_key)
    if not response  : return ""
    if response == {}: return ""

    usage = response.usage
    print(f"  prompt_tokens    : {usage.prompt_tokens}")
    print(f"  completion_tokens: {usage.completion_tokens}")

    return response.choices[0].message.content.strip()

def revise_with_openai5(text, openai_model5, role_content, prompt, effort, max_output_tokens, cfg):
#    prompt = f"{prompt}:\n翻訳してほしいテキスト\n{text}"
    prompt = process_template(prompt, { "text": text, "additional_prompt": "" })

    response = query_openai5(prompt, openai_model5, role = role_content, 
                             effort = effort, max_output_tokens = max_output_tokens,
                             openai_api_key = cfg.openai_api_key)
    if not response  : return ""
    if response == {}: return ""

    
    text = extract_openai5_text(response)
    print(f"  text: {text}")

    return text

def revise_with_google(text, google_model, role_content, prompt, temperature, max_tokens, cfg):
    if cfg.google_api_key is None: cfg.google_api_key = os.getenv("GOOGLE_API_KEY")
    if not cfg.google_api_key:
        print(f"\nError in tkai_lib.query_google(): Can not get GOOGLE_API_KEY")
        print(f"    define the environment variable GOOGLE_API_KEY\n")
        raise

#    prompt = f"{prompt}:\n翻訳してほしいテキスト\n{text}"
    prompt = process_template(prompt, 
       { 
           "text": text, 
           "additional_prompt": 
               "翻訳結果のみを出力してください。前置きや後付けのメッセージは不要です。" 
       })

    generation_config = { 
        "temperature": temperature, # 正確さ・ランダム性の制御。0.0なら正確、1.0ならランダム性高い
        "top_p": getattr(cfg, "top_p", 0.8), # 生成に使うトークンの確率範囲。1.0なら全て
        "top_k": getattr(cfg, "top_k", 40),  # top_kの候補から生成する回答を選択
        "max_output_tokens": max_tokens,
        "candidate_count": 1,
        }

    messages = [
            {
                'role': 'user',
                'parts': [role_content]
            },
            {
                'role': 'model',
                'parts': ["承知いたしました。何かお手伝いできることはありますか？"]
            },
            {
                'role': 'user',
                'parts': [prompt]
            }
        ]

    safety_settings = [
        {"category": "HARM_CATEGORY_HARASSMENT",        "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
        {"category": "HARM_CATEGORY_HATE_SPEECH",       "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
        {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
        {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
        ]

    response = query_google2(messages, google_model = "gemini-1.5-flash",
                             generation_config = generation_config, safety_settings = safety_settings,
                             google_api_key = None)

    if cfg.tsleep_rpm > 0:
        time.sleep(cfg.tsleep_rpm)

    try:
        # 応答からテキストの取得を試みる
        return response.text.strip()
    except ValueError as e:
        # response.text でエラーが発生した場合 (例: 安全フィルターによるブロック)
        print(f"\n--- [WARNING] Google APIが不正な応答を返しました (安全フィルター等)。")
        print(f"---           このテキストの翻訳をスキップします。エラー: {e}")
        print(f"---           原文: '{text[:80]}...'")
        return "" # 空文字を返して処理を続行

def translate_with_deepl(text, deepl_api_key, endpoint, source_lang = 'JA', target_lang = 'EN'):
    """
    DeepL APIを使用してテキストを翻訳する関数
    """

    response = query_deepl(text, source_lang, target_lang, 
                    deepl_api_key = deepl_api_key, endpoint = endpoint)
    if response.status_code == 200:
        result = response.json()
        text_return = extract_deepl_text(response)
        return text_return
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return text

def translate(text, api, role_content, prompt, cfg):
    if api == 'openai5':
        return revise_with_openai5(text, cfg.openai_model5, role_content, prompt, cfg.reasoning_effort, cfg.max_tokens, cfg)
    elif api == 'openai':
        return revise_with_openai4(text, cfg.openai_model, role_content, prompt, cfg.temperature, cfg.max_tokens, cfg)
    elif api == 'google':
        return revise_with_google(text, cfg.google_model, role_content, prompt, cfg.temperature, cfg.max_tokens, cfg)
    elif api == 'deepl':
        return translate_with_deepl(text, cfg.deepl_api_key, cfg.endpoint, cfg.source_lang, cfg.target_lang)
    else:
        print()
        print(f"Error in translate(): Invalid API [{api}]")
        print()
        exit()

# OpenAI APIが、どうしても英文を日本語文に変換したり余計な説明をつけるので、
# 特定のケースの翻訳をrejectする
# ・ 翻訳文の先頭が ``` の場合（念のため ''' も却下）
# ・ 翻訳文の先頭に余計な #, * を追加している場合
# ・ 翻訳文が元の文の長さよりもかなり長い場合
def check_translation(text, translated, allowed_translation_length_ratio):
    if translated is None: return False
    if translated.startswith("'''"): return False
    if translated.startswith("```"): return False

    ntranslated = n_leading_chars(translated, '#')
    ntext = n_leading_chars(text, '#')
    if ntranslated > ntext:
        return False

    ntranslated = n_leading_chars(translated, '*')
    ntext = n_leading_chars(text, '*')
    if ntranslated == ntext + 1:
        return False

    if len(translated) > len(text) * allowed_translation_length_ratio:
        return False

    return True

def translate_html(text, api, api_model, role_content, prompt, cfg):
    """
    HTMLの日本語部分を英語に翻訳
    """

    data = []
    print()
    print(">>> Analyzing html...")
    soup = BeautifulSoup(text, 'html.parser')

    print("Translating content...")
    for element in soup.find_all(string=True):  # 全てのテキストノードを取得
        if to_translate(element, cfg.min_translate_length, cfg.limit_to_multibyte_str):
            original_text = element
            revised_text = translate(element, api, role_content, prompt, cfg)
            print(f"[Original] {original_text}")
            print(f"  -> [Revised] {revised_text}")
            if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                element.replace_with(revised_text)
                data.append({ "original": original_text, "translated": revised_text})
            else:
                print(f"  *** This translation is rejected")

    return str(soup), data

def translate_pptx(ppt, api, api_model, role_content, prompt, cfg):
    data = []
    print()
    print(">>> Translating...")
    for slide in ppt.slides:
        for shape in slide.shapes:
            if shape.has_text_frame:  # テキストフレームがある場合
                for paragraph in shape.text_frame.paragraphs:
                    if cfg.process_unit == 'paragraph':
                        if to_translate(paragraph.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                            original_text = paragraph.text
                            revised_text = translate(paragraph.text, api, role_content, prompt, cfg)
                            print(f"[Original] {original_text}")
                            print(f"  -> [Revised] {revised_text}")
                            if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                                paragraph.text = revised_text
                                data.append({ "original": original_text, "translated": revised_text})
                            else:
                                print(f"  *** This translation is rejected")
                    else:
                        for run in paragraph.runs:
                            if to_translate(run.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                                original_text = run.text
                                revised_text = translate(run.text, api, role_content, prompt, cfg)
                                print(f"[Original] {original_text}")
                                print(f"  -> [Revised] {revised_text}")
                                if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                                    run.text = revised_text
                                    data.append({ "original": original_text, "translated": revised_text})
                                else:
                                    print(f"  *** This translation is rejected")
    return ppt, data

def translate_docx(doc, api, api_model, role_content, prompt, cfg):
    data = []
    print()
    print(">>> Processing paragraphs/runs...")
    if cfg.process_unit == 'paragraph':
        for paragraph in doc.paragraphs:
            if to_translate(paragraph.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                original_text = paragraph.text
                revised_text = translate(paragraph.text, api, role_content, prompt, cfg)
                print(f"[Original] {original_text}")
                print(f"  -> [Revised] {revised_text}")
                if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                    paragraph.text = revised_text
                    data.append({ "original": original_text, "translated": revised_text})
                else:
                    print(f"  *** This translation is rejected")
    else:
        for paragraph in doc.paragraphs:
            for run in paragraph.runs:
                if to_translate(run.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                    original_text = run.text
                    revised_text = translate(run.text, api, role_content, prompt, cfg)
                    print(f"[Original] {run.text}")
                    print(f"  -> [Revised] {revised_text}")
                    if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                        run.text = revised_text
                        data.append({ "original": original_text, "translated": revised_text})
                    else:
                        print(f"  *** This translation is rejected")

    print(">>> Processing tables...")
    for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    if cfg.process_unit == 'paragraph':
                        if to_translate(paragraph.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                            original_text = paragraph.text
                            revised_text = translate(paragraph.text, api, role_content, prompt, cfg)
                            print(f"[Original] {original_text}")
                            print(f"  -> [Revised] {revised_text}")
                            if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                                paragraph.text = revised_text
                                data.append({ "original": original_text, "translated": paragraph.text})
                            else:
                                print(f"  *** This translation is rejected")
                    else:
                        for run in paragraph.runs:
                            if to_translate(run.text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
                                original_text = run.text
                                revised_text = translate(run.text, api, role_content, prompt, cfg)
                                print(f"[Original] {original_text}")
                                print(f"  -> [Revised] {revised_text}")
                                if check_translation(original_text, revised_text, cfg.allowed_translation_length_ratio):
                                    run.text = revised_text
                                    data.append({ "original": original_text, "translated": revised_text})
                                else:
                                    print(f"  *** This translation is rejected")
    return doc, data

def translate_text(text, api, api_model, role_content, prompt, cfg):
    data = []
    print(">>> Translating...")
    if to_translate(text, cfg.min_translate_length, cfg.limit_to_multibyte_str):
        original_text = text
        revised_text = translate(text, api, role_content, prompt, cfg)
        print(f"[Original] {original_text}")
        print(f"  -> [Revised] {revised_text}")
        data.append({ "original": original_text, "translated": revised_text})

    return revised_text, data

def execute(cfg):
    filetype = get_filetype(cfg.infile)
    if cfg.process_unit == 'md':
        cfg.use_md = 1
    else:
        cfg.use_md = 0

    if filetype == 'md':
        outfile = replace_path(mdfile, "_revised.md")
    elif cfg.use_md:
        mdfile = replace_path(cfg.infile, ".md")
        outfile = replace_path(mdfile, "_revised.md")
    elif filetype == 'pdf':
        if cfg.use_md:
            outfile = replace_path(mdfile, "_revised.md")
        else:
            outfile = replace_path(cfg.infile, "_revised.docx")
    elif filetype == 'docx':
        outfile = replace_path(cfg.infile, "_revised.docx")
    elif filetype == 'html':
        outfile = replace_path(cfg.infile, "_revised.html")
    elif filetype == 'pptx':
        outfile = replace_path(cfg.infile, "_revised.pptx")
    else:
        print(f"\nError in execute(): Invalid extension in [{cfg.infile}]\n")
        exit()
        
    output_comparison_html_path = replace_path(cfg.infile, '_compare.html')
    output_reformat_md = replace_path(cfg.infile, "_reformat.md")
    output_docx = replace_path(cfg.infile, ".docx")

    print("=== Translate and revise .docx/.pptx/.pdf/.html/.md file ===")
    print(f"  Input file            : {cfg.infile}")
    print(f"    file type           : {filetype}")
    print(f"  API                   : {cfg.api}")
    if cfg.api == "openai5":
        print(f"  openai_model          : {cfg.openai_model5}")
#        print(f"  deepl_api_key         : {os.getenv('DEEPL_API_KEY')}")
    elif cfg.api == "openai":
        print(f"  openai_model          : {cfg.openai_model}")
#        print(f"  deepl_api_key         : {os.getenv('DEEPL_API_KEY')}")
    elif cfg.api == "google":
        print(f"  google_model          : {cfg.google_model}")
#        print(f"  google_api_key        : {os.getenv('GOOGLE_API_KEY')}")
    elif cfg.api == "deepl":
#        print(f"  deepl_api_key         : {os.getenv('DEEPL_API_KEY')}")
        pass

    print(f"  Translation mode      : {cfg.mode}")
    print(f"  limit_to_multibyte_str: {cfg.limit_to_multibyte_str}")
    print(f"  min_translate_length  : {cfg.min_translate_length}")
    print(f"  allowed_translation_length_ratio: {cfg.allowed_translation_length_ratio}")
    print(f"  Output file           : {outfile}")
    print(f"  Template HTML file    : {cfg.html_template_path}")
    print(f"  Output compare file   : {output_comparison_html_path}")
    print(f"  Use markdown : {cfg.use_md}")
    if cfg.use_md:
        print(f"  Markdown file: {mdfile}")
        if filetype == 'pdf':
            print(f"  Reformat markdown file: {output_reformat_md}")
            print(f"  reformat role         : {cfg.reformat_role}")
            print(f"  reformat prompt       : {cfg.reformat_prompt}")
    else:
        if filetype == 'docx' or filetype == 'pdf':
            print(f"  Process unit : {cfg.process_unit}")
            if filetype == 'pdf':
                print(f"  Converted docx file: {output_docx}")
    if "openai" in cfg.api or cfg.api == "google" or cfg.infile.endswith('.pdf'):
        print(f"  translate role  : {cfg.translate_role}")
        print(f"  translate prompt: {cfg.translate_prompt}")
    
    print()
    if os.path.isfile(cfg.infile) == False:
        print(f"Error: File [{cfg.infile}] does not exist")
        usage()
        exit()

    if filetype == 'md' or filetype == 'txt':
        print(f"Read [{cfg.infile}]")
        text = read_file(cfg.infile)
        text, data = translate_text(text, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
        if text is None:
            print(f"Error for filetype = {filetype}: Could not get text")
            exit()
        print(f"=== Saving revised text to {outfile} ===")
        save(outfile, text)
        exit()
    elif cfg.use_md:
        print(f"Read [{cfg.infile}] and convert to markdown")
        text = convert_to_md(cfg.infile)
        if text is None:
            print(f"Error for md: Could not get text")
            exit()
        print(f"=== Saving markdown to  {mdfile} ===")
        save(mdfile, text)

# PDFファイルの場合は、ChatGPT/Geminiで文書を整えなおす
        if filetype == 'pdf':
            print(f"Reformatting [{mdfile}] by OpenAI...")
            if cfg.api == 'openai5':
                text = revise_with_openai5(text, cfg.openai_model, cfg.reformat_role, cfg.reformat_prompt, cfg.reasoning_effort, cfg.max_tokens)
            elif cfg.api == 'openai':
                text = revise_with_openai4(text, cfg.openai_model, cfg.reformat_role, cfg.reformat_prompt, cfg.temperature, cfg.max_tokens)
            elif cfg.api == "google":
                text = revise_with_google(text, cfg.google_model, cfg.reformat_role, cfg.reformat_prompt, cfg.temperature, cfg.max_tokens)
            else:
                print(f"Error: API [{cfg.api}] is unable to reformat PDF text")
                exit()

            if text is None:
                print(f"Error: Could not get reformatted text")
                exit()
            print(f"Reformatted MD file is saved to [{output_reformat_md}]")
            save(output_reformat_md, text)

        text, data = translate_text(text, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
        if text is None:
            print(f"Error in getting translated text: Could not get text")
            exit()
        print(f"=== Saving revised text to {outfile} ===")
        save(outfile, text)

    if not cfg.use_md:
        if filetype == 'pdf':
            print(f"Converting [{cfg.infile}] to [{output_docx}]")
            pdf_to_docx(cfg.infile, output_docx)
            print(f"Read [{output_docx}]")
            doc = Document(output_docx)
            doc, data = translate_docx(doc, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
            print(f"=== Saving revised text to {outfile} ===")
            doc.save(outfile)
        elif filetype == 'pptx':
            ppt = Presentation(cfg.infile)
            ppt, data = translate_pptx(ppt, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
            print(f"=== Saving revised text to {outfile} ===")
            ppt.save(outfile)
        elif filetype == 'docx':
            print(f"Read [{cfg.infile}]")
            doc = Document(cfg.infile)
            doc, data = translate_docx(doc, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
            print(f"=== Saving revised text to {outfile} ===")
            doc.save(outfile)
        elif filetype == 'html':
            print(f"Read [{cfg.infile}]")
            html = read_file(cfg.infile)
            html, data = translate_html(html, cfg.api, cfg.openai_model, cfg.translate_role, cfg.translate_prompt, cfg)
            print(f"=== Saving revised text to {outfile} ===")
            save(outfile, html)

# ------------------------------------------------------
# テンプレート処理
# ------------------------------------------------------
    print()
    print(f"Creating comparison HTML file from template [{cfg.html_template_path}]")
    context = cfg.__dict__.copy()
    context["data"] = data

    # 1. 検索パスを定義 (カレントディレクトリ -> スクリプトディレクトリ)
    current_dir = os.getcwd()
    script_dir = os.path.dirname(os.path.abspath(__file__))
    
    if not os.path.isfile(cfg.html_template_path):
        template_filename = os.path.basename(cfg.html_template_path)
        cfg.html_template_path = os.path.join(current_dir, template_filename)
    if not os.path.isfile(cfg.html_template_path):
        template_filename = os.path.basename(cfg.html_template_path)
        cfg.html_template_path = os.path.join(script_dir, template_filename)
    print(f"  Template path: [{cfg.html_template_path}]")

    # 4. テンプレートが見つかった場合のみレポートを生成
    if os.path.isfile(cfg.html_template_path):
        template_dir = os.path.dirname(cfg.html_template_path)
        template_file = os.path.basename(cfg.html_template_path)

        env = Environment(loader=FileSystemLoader(template_dir))
        template = env.get_template(template_file)
        
        rendered_html = template.render(context)

        print()
        print(f"Save translation data to [{output_comparison_html_path}]")
        with open(output_comparison_html_path, 'w', encoding='utf-8') as file:
            file.write(rendered_html)
    else:
        # テンプレートが見つからなかった場合、警告を表示してスキップ
        print()
        print(f"--- [WARNING] Template file '{cfg.html_template_path}' not found.")
        print(f"---           Looked in current and script directories.")
        print("---           Skipping generation of comparison HTML report.")
    
    print()

def main():
    global parser
    
    cfg, parser = initialize()
    cfg = update_variables(cfg, parser)

    execute(cfg)

if __name__ == "__main__":
    main()
    print()
    usage()
    
    input("\nPress ENTER to terminate>>\n")
    
