import os
import sys
try:
    from dotenv import load_dotenv
except:
    print("Error in tkai_lib: Failed to import dotenv")
    input("Install: pip install dotenv")

try:
    import openai
except Exception as e:
    print(f"\nWarning in tkai_lib: Can not import openai: {e}")
    print(f"   Install: pip install openai\n")
    openai = None

try:
    from openai import OpenAI
except Exception as e:
    print(f"\nWarning in tkai_lib: cannot import OpenAI SDK: {e}")
    print("   Install: pip install --upgrade openai\n")
    OpenAI = None

try:
    import google.generativeai as genai
except Exception as e:
    print(f"\nWarning in tkai_lib: Can not import google.generativeai: {e}")
    print(f"   Install: pip install google.generativeai\n")
    genai = None
try:
    from google.api_core import exceptions as gexceptions
except Exception as e:
    print(f"\nWarning in tkai_lib: Can not import google.api_core.exceptions: {e}")
    print(f"   Install: pip install google.api_core\n")
    gexceptions = None

try:
    import requests
except:
    print(f"\nWarning in tkai_lib: Can not import requests: {e}")
    input(f"    Install: pip install requests")
    requests = None


def read_ai_config(config_path: str = "translate.env", read_account_inf = True):
    if not os.path.exists(config_path):
        script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
        config_path = os.path.join(script_dir, config_path)

    print()
# config_pathから環境変数読み込み
    if os.path.isfile(config_path):
        print(f"config_path: {config_path}")
    else:
        print(f"Warning: config_path {config_path} is not found")
    load_dotenv(dotenv_path = config_path)

# config_pathからaccount_pathを取得、account_pathから環境変数読み込み
    if read_account_inf:
        account_inf_path = os.getenv("account_inf_path", "accounts.env")
        if os.path.isfile(account_inf_path):
            print(f"account_inf_path: {account_inf_path}")
        else:
            print(f"Warning: account_inf_path {account_inf_path} is not found")
        load_dotenv(dotenv_path = account_inf_path)

def openai_response_to_json(response):
    json = eval(response.choices[0].message.content)
    if type(json) is list or type(json) is tuple:
        return json[0], json
    else:
        return json, [json]

def extract_openai5_text(response) -> str | None:
    """response.output から 'message' の output_text を手動抽出。"""
    try:
        # まず SDK の便利プロパティを試す（ある場合はこれが楽）
        txt = getattr(response, "output_text", None)
        if txt:
            return txt
    except Exception:
        pass

    # フォールバック: 出力配列をなめて message の output_text を拾う
    texts = []
    for item in getattr(response, "output", []) or []:
        if getattr(item, "type", None) == "message":
            for c in getattr(item, "content", []) or []:
                if c.get("type") == "output_text" and "text" in c:
                    texts.append(c["text"])
    return "\n".join(texts) if texts else None

    '''
    text = getattr(resp, "output_text", None)
    if not text:
        pieces = []
        for item in getattr(resp, "output", []) or []:
            if getattr(item, "type", None) == "message":
                # 出力メッセージには role='assistant' が入ります（仕様）:contentReference[oaicite:1]{index=1}
                for c in (item.content or []):
                    if c.get("type") == "output_text" and "text" in c:
                        pieces.append(c["text"])
        text = "\n".join(pieces).strip()
    '''


def openai5_response_to_json(response):
    text = extract_openai5_text(response)
    json = eval(text)
    if type(json) is list or type(json) is tuple:
        return json[0], json
    else:
        return json, [json]

def google_response_to_json(response):
    json = eval(response.text)
    if type(json) is list or type(json) is tuple:
        return json[0], json
    else:
        return json, [json]

def query_openai4(prompt, openai_model = "gpt-4o", role = None, response_format = None,
                    temperature = 0.7, max_tokens = 1000,
                    openai_api_key = None):
    if openai is None: return False
    if openai_api_key is None: openai_api_key = os.getenv("OPENAI_API_KEY")
    if not openai_api_key:
        print(f"\nError in tkai_lib.query_openai(): Can not get OPENAI_API_KEY")
        print(f"    define the environment variable OPENAI_API_KEY\n")
        return False

    openai.api_key = openai_api_key
    response = None
    kw = {
        "model": openai_model,
        "temperature": temperature,
        "max_tokens": max_tokens,
        }
    if role is None:
        kw["messages"] = [
                {"role": "user", "content": prompt}
            ]
    else:
        kw["messages"] = [
                {"role": "system", "content": role},
                {"role": "user",   "content": prompt}
            ]

    if response_format is not None:
        kw["response_format"] = response_format

    try:
        response = openai.chat.completions.create(**kw)
    except Exception as e:
        print(f"\nError in tkai_lib.query_openai(): Error in calling OpenAI API: {e}")
        print("  response:", response)
        return {}

    return response

def query_openai5(
    prompt,
    openai_model="gpt-5",
    instructions=None,
    role=None,                         # 例: "user" / "system" / "assistant"
    effort="minimal",                  # "minimal" | "low" | "medium" | "high"
    max_output_tokens=1024,
    store=False,
    response_format=None,              # 例: {"type": "json_object"} or {"type":"json_schema","json_schema":{...}}
    openai_api_key=None,
):
    """
    GPT-5（Responses API）用の最小関数。
    - prompt: str あるいは Responses APIの input 用オブジェクト配列
    - openai_model: "gpt-5" / "gpt-5-mini" など
    - instructions: system相当の一括方針
    - response_format: JSONモードや構造化出力を使う場合の dict
    - effort: "minimal" | "low" | "medium" | "high"
    - max_output_tokens: 出力トークン上限
    戻り値: response オブジェクト（テキストは response.output_text で取得可）
    """

    if openai_api_key is None:
        openai_api_key = os.getenv("OPENAI_API_KEY")
    if not openai_api_key:
        print("\nError in query_openai5(): OPENAI_API_KEY is not set")
        print("    define the environment variable OPENAI_API_KEY\n")
        return None

    client = OpenAI(api_key=openai_api_key)

    # ベースのパラメータ
    kw = {
        "model": openai_model,
        "max_output_tokens": max_output_tokens,
        "store": store,
    }

    if effort is not None:
        kw["reasoning"] = {"effort": effort}

    if instructions is not None:
        kw["instructions"] = instructions

    if response_format is not None:
        kw["response_format"] = response_format

    if isinstance(prompt, list):
        kw["input"] = prompt
    elif role is not None:
        kw["input"] = [
                {"role": "system", "content": role},
                {"role": "user",   "content": prompt}
            ]
    else:
        kw["input"] = prompt

    try:
        response = client.responses.create(**kw)
    except Exception as e:
        print(f"\nError in query_openai5(): API call failed: {e}")
        return None

    return response

def query_google(prompt, google_model = "gemini-2.5-flash",
                role = None, generation_config = None,
                google_api_key = None):
    if genai is None: return False
    if google_api_key is None: google_api_key = os.getenv("GOOGLE_API_KEY")
    if not 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")
        return False

    if role is not None:
        args = [
            {
            "contents": [
                {"role": "system", "parts": [role]},
                {"role": "user", "parts": [prompt]}
                ]
            }
        ]
        if generation_config is not None:
            args[0]["generation_config"] = generation_config # {"response_mime_type": "application/json"} }
    else:
        args = [prompt]
        if generation_config is not None:
            args.append(
                { "generation_config": generation_config } # {"response_mime_type": "application/json"} }
                )

    genai.configure(api_key = google_api_key)
    model = genai.GenerativeModel(google_model)
    response = None
    try:
#        response = model.generate_content(*args)
        response = model.generate_content(
            prompt,
            generation_config=generation_config,
        )
    except Exception as e:
        print(f"\nError in tkai_lib.query_google(): Error in calling GOOGLE API: {e}")
        print("  response:", response)
        return {}

    return response

def query_google2(messages, google_model = "gemini-2.5-flash",
                generation_config = None, safety_settings = None,
                google_api_key = None):
    if genai is None: return False
    if google_api_key is None: google_api_key = os.getenv("GOOGLE_API_KEY")
    if not 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")
        return False

    if generation_config is None:
        generation_config = { 
            "temperature": 0.7, # 正確さ・ランダム性の制御。0.0なら正確、1.0ならランダム性高い
            "top_p"      : 0.8, # 生成に使うトークンの確率範囲。1.0なら全て
            "top_k"      : 40,  # top_kの候補から生成する回答を選択
            "max_output_tokens": 1500,
            "candidate_count"  : 1,
            }

    if safety_settings is None:
        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"},
            ]

    model = genai.GenerativeModel(google_model)
    genai.configure(api_key = google_api_key)
    try:
        response = model.generate_content(
            messages,
            generation_config = generation_config,
            safety_settings = safety_settings,
            )
    except gexceptions.ResourceExhausted as e: 
        print(f"Error in revise_with_google(): google APIエラーが発生しました: {e}")
        if e.code == 429:  # レート制限のエラーコードの例
            print("   出力クォータに達しました。時間をおいてから再度お試しください。")
            return None
        else:
            print(f"   エラー詳細 (コード: {e.code}): {e.message}")
    except Exception as e:
        print(f"Error in revise_with_google(): 予期せぬエラーが発生しました: {e}")
        return None

    if response and hasattr(response, "parts"):
        pass
    else:
        print("Error in revise_with_google(): 応答がありませんでした。")

    if response.prompt_feedback:
        if response.prompt_feedback.block_reason:
            print(f"Error in revise_with_google(): プロンプトがブロックされました。理由: {response.prompt_feedback.block_reason}")
            if response.prompt_feedback.safety_ratings:
                print("安全性評価:")
                for rating in response.prompt_feedback.safety_ratings:
                    print(f"- カテゴリ: {rating.category}, 評価: {rating.probability}")
            return None

    return response


def extract_deepl_text(response) -> str | None:
    if response.status_code == 200:
        result = response.json()
        return result["translations"][0]["text"]
    else:
        return None

def query_deepl(text, source_lang = "JA", target_lang = "EN", 
                    deepl_api_key = None, endpoint = "free"):
    if requests is None: return False
    
    if endpoint == "free":
        endpoint = "https://api-free.deepl.com/v2/translate"
    elif endpoint == "pro":
        endpoint = "https://api.deepl.com/v2/translate"

    headers = {"Authorization": f"DeepL-Auth-Key {deepl_api_key}"}
    params = {
        "text": text,
        "source_lang": source_lang,
        "target_lang": target_lang,
        "tag_handling": "xml"  # DeepLにXMLタグ（<tag>形式）を無視させる
    }
    response = requests.post(endpoint, headers = headers, data = params)
    if response.status_code == 200:
        return response
    if response.status_code == 403:
        print(f"Error in query_deepl(): Forbidden acecss {response.status_code}: {response.text}")
        print(f"  Check access information like api key and endpoint")
        return respoonse
    else:
        print(f"Error in query_deepl(): {response.status_code}: {response.text}")
        return None
            
def query(prompt: str, api: str, api_key: str, model: str):
    try:
        if api == 'gemini' or api == 'google':
            print(f"Gemini API [{model}] を呼び出しています...")
            genai.configure(api_key=api_key)
            model = genai.GenerativeModel(model)
            response = model.generate_content(prompt)
            return response.text, response

        elif api == 'openai5':
            # GPT-5系やResponses API対応モデルを想定
            print(f"OpenAI Responses API（openai5） [{model}] を呼び出しています...")
            client = OpenAI(api_key=api_key)
            # 単純なテキスト入力なら input に文字列でOK
            response = client.responses.create(
                model=model,       # 例: "gpt-5", "gpt-5-mini", "gpt-5-chat"
                input=prompt
                # もし役割付きメッセージで送りたい場合は:
                # input=[{"role":"user","content":prompt}]
            )
            return response.output_text or "", response

        elif api == 'openai':
            print(f"OpenAI API（Chat Completions） [{model}] を呼び出しています...")
            client = OpenAI(api_key=api_key)
            response = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": prompt}]
            )
            return response.choices[0].message.content, response

        else:
            print(f"Error in tkai_lib.query(): 未対応の str: {api}", file=sys.stderr)
            return None, None

    except Exception as e:
        print(f"Error in tkai_lib.query(): API呼び出し中にエラーが発生しました: {e}", file=sys.stderr)
        return None, None

