import sys
import os
import traceback
import argparse
import yaml
import json
import logging as py_logging
from typing import Annotated
from pydantic import Field

# Initialize logging
py_logging.basicConfig(level=py_logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# Support relative imports
try:
    from .recursive_thinking_ai import EnhancedRecursiveThinkingChat
    py_logging.debug("Imported EnhancedRecursiveThinkingChat via relative import")
except ImportError as e:
    py_logging.debug(f"Relative import failed: {e}, trying absolute import")
    try:
        # When executed directly
        from cort_mcp.recursive_thinking_ai import EnhancedRecursiveThinkingChat
        py_logging.debug("Imported EnhancedRecursiveThinkingChat via absolute import")
    except ImportError as e2:
        py_logging.debug(f"Absolute import failed: {e2}, trying sys.path modification")
        # When executed in development mode
        src_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        py_logging.debug(f"Adding path to sys.path: {src_path}")
        sys.path.append(src_path)
        try:
            from recursive_thinking_ai import EnhancedRecursiveThinkingChat
            py_logging.debug("Imported EnhancedRecursiveThinkingChat via sys.path modification")
        except ImportError as e3:
            py_logging.error(f"All import attempts failed: {e3}")
            raise

# Import MCP server library
try:
    from fastmcp import FastMCP
    py_logging.debug("Imported FastMCP from fastmcp package")
except ImportError as e:
    py_logging.debug(f"Import from fastmcp failed: {e}, trying mcp.server.fastmcp")
    try:
        from mcp.server.fastmcp import FastMCP
        py_logging.debug("Imported FastMCP from mcp.server.fastmcp")
    except ImportError as e2:
        py_logging.error(f"Failed to import FastMCP: {e2}")
        raise

# Define default values as constants
DEFAULT_MODEL = "mistralai/mistral-small-3.1-24b-instruct:free"
DEFAULT_PROVIDER = "openrouter"

# --- Logging Setup ---
def setup_logging(log: str, logfile: str):
    print(f"[DEBUG_SETUP] setup_logging called with log='{log}', logfile='{logfile}'", file=sys.stderr)
    if log == "on":
        if not logfile or not logfile.startswith("/"):
            print("[FATAL_SETUP] --logfile must be an absolute path when --log=on", file=sys.stderr)
            sys.exit(1)

        log_dir = os.path.dirname(logfile)
        print(f"[DEBUG_SETUP] Attempting to use log directory: {log_dir}", file=sys.stderr)
        if not os.path.exists(log_dir):
            print(f"[DEBUG_SETUP] Log directory {log_dir} does not exist. Attempting to create.", file=sys.stderr)
            try:
                os.makedirs(log_dir, exist_ok=True)
                print(f"[INFO_SETUP] Successfully created log directory: {log_dir}", file=sys.stderr)
            except Exception as e:
                print(f"[FATAL_SETUP] Failed to create log directory: {log_dir} error={e}", file=sys.stderr)
                traceback.print_exc(file=sys.stderr)
                sys.exit(1)
        else:
            print(f"[DEBUG_SETUP] Log directory {log_dir} already exists.", file=sys.stderr)
        if os.path.exists(log_dir) and not os.access(log_dir, os.W_OK | os.X_OK):
            print(f"[WARNING_SETUP] Log directory {log_dir} exists but may not be writable/executable by current user (UID: {os.getuid()})!", file=sys.stderr)

        try:
            print(f"[DEBUG_SETUP] Attempting to initialize FileHandler with logfile: {logfile}", file=sys.stderr)
            root_logger = py_logging.getLogger()
            print(f"[DEBUG_SETUP] Root logger obtained: {root_logger}. Current handlers: {root_logger.handlers}", file=sys.stderr)
            for handler in root_logger.handlers[:]:
                print(f"[DEBUG_SETUP] Removing handler {handler} from root logger.", file=sys.stderr)
                root_logger.removeHandler(handler)
            root_logger.setLevel(py_logging.DEBUG)
            print(f"[DEBUG_SETUP] Root logger handlers cleared and level set to DEBUG.", file=sys.stderr)

            # Add only FileHandler to root logger
            file_handler = py_logging.FileHandler(logfile, mode="a", encoding="utf-8")
            file_handler.setLevel(py_logging.DEBUG)
            formatter = py_logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
            file_handler.setFormatter(formatter)
            root_logger.addHandler(file_handler)
            print(f"[DEBUG_SETUP] FileHandler added to root logger. Root logger handlers: {root_logger.handlers}", file=sys.stderr)

            # Also add StreamHandler (stdout)
            stream_handler = py_logging.StreamHandler(sys.stderr) # Output debug to stderr
            print(f"[DEBUG_SETUP] StreamHandler (stderr) initialized. Attempting to add to root_logger.", file=sys.stderr)
            stream_handler.setLevel(py_logging.DEBUG)
            stream_handler.setFormatter(formatter)
            root_logger.addHandler(stream_handler)
            print(f"[DEBUG_SETUP] StreamHandler (stderr) added to root logger. Root logger handlers: {root_logger.handlers}", file=sys.stderr)

            # Explicitly call flush
            # file_handler.flush() # Typically not needed immediately, OS handles buffering
            # print(f"[DEBUG_SETUP] FileHandler flushed for {logfile}.", file=sys.stderr)

            # Set global logger as well
            specific_logger = py_logging.getLogger("cort-mcp-server")
            # specific_logger.handlers.clear() # Not needed if propagate is True and root is configured
            specific_logger.setLevel(py_logging.DEBUG)
            # specific_logger.addHandler(file_handler) # Already on root
            # specific_logger.addHandler(stream_handler) # Already on root
            specific_logger.propagate = True # Let root logger handle it
            print(f"[DEBUG_SETUP] Specific logger 'cort-mcp-server' configured. Propagate: {specific_logger.propagate}. Handlers: {specific_logger.handlers}. Effective level: {specific_logger.getEffectiveLevel()}", file=sys.stderr)

            py_logging.debug("[DEBUG_SETUP_TEST_ROOT] Root logger test: Logging configured.")
            specific_logger.debug(f"[DEBUG_SETUP_TEST_SPECIFIC] Specific logger 'cort-mcp-server' test: Log initialized for {logfile}")
            print(f"[INFO_SETUP] MCP Server log initialization attempted for (print): {logfile}", file=sys.stderr)

            if os.path.exists(logfile):
                print(f"[INFO_SETUP] Log file {logfile} exists after FileHandler setup (print).", file=sys.stderr)
                specific_logger.info(f"Log file {logfile} exists after FileHandler setup.")
                try:
                    with open(logfile, "a", encoding="utf-8") as f_test:
                        f_test.write(f"TEST_WRITE_SUCCESS at {py_logging.Formatter('%(asctime)s').format(py_logging.LogRecord(name='test-write', level=py_logging.INFO, pathname='', lineno=0, msg='', args=(), exc_info=None, func=''))}\n")
                    print(f"[INFO_SETUP] Successfully wrote a test line to {logfile}.", file=sys.stderr)
                except Exception as e_write:
                    print(f"[ERROR_SETUP] Failed to write a test line to {logfile}: {e_write}", file=sys.stderr)
                    specific_logger.error(f"Failed to write a test line to {logfile}: {e_write}")

            else:
                print(f"[WARNING_SETUP] Log file {logfile} was NOT created or is not visible after FileHandler setup (print).", file=sys.stderr)
                specific_logger.warning(f"Log file {logfile} was NOT created or is not visible after FileHandler setup.")

            return specific_logger
        except Exception as e:
            print(f"[FATAL_SETUP] Failed to create log file or setup handler: {logfile} error={e}", file=sys.stderr)
            traceback.print_exc(file=sys.stderr)
            sys.exit(1)
    elif log == "off":
        # Completely disable logging functionality
        py_logging.disable(py_logging.CRITICAL + 1) # Disable all levels including CRITICAL
        print("[INFO_SETUP] Logging disabled (--log=off)", file=sys.stderr)
        return None
    else:
        print("[FATAL_SETUP] --log must be 'on' or 'off'", file=sys.stderr)
        sys.exit(1)

def resolve_model_and_provider(params):
    print("=== resolve_model_and_provider called ===")
    py_logging.info("=== resolve_model_and_provider called ===")
    import os
    # Use existing py_logging (already imported as py_logging)
    # Debug: Output environment variable status
    def mask_key(key):
        if key:
            return 'SET'
        return 'NOT_SET'
    py_logging.info(f"[DEBUG] ENV OPENROUTER_API_KEY={mask_key(os.getenv('OPENROUTER_API_KEY'))}")
    py_logging.info(f"[DEBUG] ENV OPENAI_API_KEY={mask_key(os.getenv('OPENAI_API_KEY'))}")
    # params: dict
    model = params.get("model")
    provider = params.get("provider")
    py_logging.info(f"[DEBUG] params: model={model}, provider={provider}")
    if not model:
        model = DEFAULT_MODEL
    if not provider:
        provider = DEFAULT_PROVIDER
    py_logging.info(f"[DEBUG] after default: model={model}, provider={provider}")
    # Check API key existence here (including invalid/unset provider)
    api_key = get_api_key(provider)
    py_logging.info(f"[DEBUG] get_api_key(provider={provider}) -> {mask_key(api_key)}")
    if not api_key:
        # Invalid provider or no API key -> fallback to default
        provider = DEFAULT_PROVIDER
        model = DEFAULT_MODEL
        api_key = get_api_key(provider)
        py_logging.info(f"[DEBUG] fallback: model={model}, provider={provider}, api_key={mask_key(api_key)}")
    # Additional checks like "model not existing in provider" are detected by exceptions in AI-side API
    return model, provider, api_key

def get_api_key(provider):
    if provider == "openai":
        key = os.getenv("OPENAI_API_KEY")
    elif provider == "openrouter":
        key = os.getenv("OPENROUTER_API_KEY")
    else:
        key = None
    return key

# Create FastMCP instance
server = FastMCP(
    name="Chain-of-Recursive-Thoughts MCP Server",
    instructions="Provide deeper recursive thinking and reasoning for the given prompt. Use the MCP Server when you encounter complex problems.",
)

# Define tools using decorators
@server.tool(
    name="cort.think.simple",
    description="""
    Return a simple recursive thinking AI response.

    Parameters:
        prompt (str, required): Input prompt for the AI.
        model (str, optional): LLM model name. If not specified, uses default.
        provider (str, optional): API provider name. If not specified, uses default.

    Returns:
        dict: {
            "response": AI response (string),
            "model": model name used (string),
            "provider": provider name used (string)
        }

    Notes:
        - If model/provider is omitted, defaults are used.
        - Do not pass null or empty string for optional params.
        - See README for fallback logic on API errors.
    """
)
async def cort_think_simple(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")],
    model: Annotated[str | None, Field(description="LLM model name. If not specified, uses default.")]=None,
    provider: Annotated[str | None, Field(description="API provider name. If not specified, uses default.")]=None
):
    resolved_model, resolved_provider, api_key = resolve_model_and_provider({"model": model, "provider": provider})
    py_logging.info(f"cort_think_simple called: prompt={prompt} model={resolved_model} provider={resolved_provider}")
    if not prompt:
        py_logging.warning("cort_think_simple: prompt is required")
        return {
            "error": "prompt is required"
        }
    try:
        chat = EnhancedRecursiveThinkingChat(api_key=api_key, model=resolved_model, provider=resolved_provider)
        result = chat.think(prompt, details=False)
        py_logging.info("cort_think_simple: result generated successfully")
        return {
            "response": result.get("response"),
            "model": result.get("model"),
            "provider": result.get("provider")
        }
    except Exception as e:
        py_logging.exception(f"[ERROR] cort_think_simple failed: {e}")
        fallback_api_key = get_api_key(DEFAULT_PROVIDER)
        if fallback_api_key:
            try:
                chat = EnhancedRecursiveThinkingChat(api_key=fallback_api_key, model=DEFAULT_MODEL, provider=DEFAULT_PROVIDER)
                result = chat.think(prompt, details=False)
                py_logging.info("cort_think_simple: fallback result generated successfully")
                return {
                    "response": result.get("response"),
                    "model": result.get("model"),
                    "provider": result.get("provider")
                }
            except Exception as e2:
                py_logging.exception(f"[ERROR] cort_think_simple fallback also failed: {e2}")
                return {
                    "error": f"Failed to process request: {str(e)}. Fallback also failed: {str(e2)}"
                }
        else:
            py_logging.error("cort_think_simple: API key for OpenAI is missing (cannot fallback)")
            return {
                "error": f"Failed to process request: {str(e)}. API key for OpenAI is missing (cannot fallback)"
            }

@server.tool(
    name="cort.think.simple.neweval",
    description="""
    Return a simple recursive thinking AI response (new evaluation prompt version).

    Parameters:
        prompt (str, required): Input prompt for the AI.
        model (str, optional): LLM model name. If not specified, uses default.
        provider (str, optional): API provider name. If not specified, uses default.

    Returns:
        dict: {
            "response": AI response (string),
            "model": model name used (string),
            "provider": provider name used (string)
        }

    Notes:
        - If model/provider is omitted, defaults are used.
        - Do not pass null or empty string for optional params.
        - See README for fallback logic on API errors.
    """
)
async def cort_think_simple_neweval(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")],
    model: Annotated[str | None, Field(description="LLM model name. If not specified, uses default.")]=None,
    provider: Annotated[str | None, Field(description="API provider name. If not specified, uses default.")]=None
):
    resolved_model, resolved_provider, api_key = resolve_model_and_provider({"model": model, "provider": provider})
    py_logging.info(f"cort_think_simple_neweval called: prompt={prompt} model={resolved_model} provider={resolved_provider}")
    if not prompt:
        py_logging.warning("cort_think_simple_neweval: prompt is required")
        return {
            "error": "prompt is required"
        }
    try:
        chat = EnhancedRecursiveThinkingChat(api_key=api_key, model=resolved_model, provider=resolved_provider)
        result = chat.think(prompt, details=False, neweval=True)
        py_logging.info("cort_think_simple_neweval: result generated successfully")
        return {
            "response": result.get("response"),
            "model": result.get("model"),
            "provider": result.get("provider")
        }
    except Exception as e:
        py_logging.exception(f"[ERROR] cort_think_simple_neweval failed: {e}")
        fallback_api_key = get_api_key(DEFAULT_PROVIDER)
        if fallback_api_key:
            try:
                chat = EnhancedRecursiveThinkingChat(api_key=fallback_api_key, model=DEFAULT_MODEL, provider=DEFAULT_PROVIDER)
                result = chat.think(prompt, details=False, neweval=True)
                py_logging.info("cort_think_simple_neweval: fallback result generated successfully")
                return {
                    "response": result["response"],
                    "model": DEFAULT_MODEL,
                    "provider": f"{DEFAULT_PROVIDER} (fallback)"
                }
            except Exception as e2:
                py_logging.exception(f"[ERROR] cort_think_simple_neweval fallback also failed: {e2}")
                return {
                    "error": f"Failed to process request: {str(e)}. Fallback also failed: {str(e2)}"
                }
        else:
            py_logging.error("cort_think_simple_neweval: API key for OpenAI is missing (cannot fallback)")
            return {
                "error": f"Failed to process request: {str(e)}. API key for OpenAI is missing (cannot fallback)"
            }

@server.tool(
    name="cort.think.details",
    description="""
    Returns a recursive thinking AI response with full reasoning details.

    Parameters:
        prompt (str, required): Input prompt for the AI.
        model (str, optional): LLM model name. If not specified, the default model is used.
        provider (str, optional): API provider name. If not specified, the default provider is used.

    Returns:
        dict: {
            "response": Final AI response (string),
            "details": Reasoning process history (YAML string),
            "model": Model name used (string),
            "provider": Provider name used (string)
        }

    Notes:
        - If model/provider is omitted, defaults are applied automatically.
        - On exceptions, fallback logic is applied.
        - Reasoning history is included in the 'details' key as YAML.
    """
)
async def cort_think_details(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")],
    model: Annotated[str | None, Field(description="LLM model name to use.\n- Recommended (OpenAI): 'gpt-4.1-nano'\n- Recommended (OpenRouter): 'meta-llama/llama-4-maverick:free'\n- Default: mistralai/mistral-small-3.1-24b-instruct:free\nRefer to the official provider list for available models. If not specified, the default model will be used automatically.")]=None,
    provider: Annotated[str | None, Field(description="API provider name to use.\n- Allowed: 'openai' or 'openrouter'\n- Default: openrouter\nModel availability depends on the provider. Please ensure the correct combination. If not specified, the default provider will be used automatically.")]=None
):
    resolved_model, resolved_provider, api_key = resolve_model_and_provider({"model": model, "provider": provider})
    py_logging.info(f"cort_think_details called: prompt={prompt} model={resolved_model} provider={resolved_provider}")
    if not prompt:
        py_logging.warning("cort_think_details: prompt is required")
        return {
            "error": "prompt is required"
        }
    try:
        chat = EnhancedRecursiveThinkingChat(api_key=api_key, model=resolved_model, provider=resolved_provider)
        result = chat.think(prompt, details=True)
        yaml_log = yaml.safe_dump({
            "thinking_rounds": result.get("thinking_rounds"),
            "thinking_history": result.get("thinking_history")
        }, allow_unicode=True, sort_keys=False)
        py_logging.info("cort_think_details: result generated successfully")
        return {
            "response": result["response"],
            "details": yaml_log,
            "model": resolved_model,
            "provider": resolved_provider
        }
    except Exception as e:
        py_logging.exception(f"[ERROR] cort_think_details failed: {e}")
        fallback_api_key = get_api_key(DEFAULT_PROVIDER)
        if fallback_api_key:
            try:
                chat = EnhancedRecursiveThinkingChat(api_key=fallback_api_key, model=DEFAULT_MODEL, provider=DEFAULT_PROVIDER)
                result = chat.think(prompt, details=True)
                yaml_log = yaml.safe_dump({
                    "thinking_rounds": result.get("thinking_rounds"),
                    "thinking_history": result.get("thinking_history")
                }, allow_unicode=True, sort_keys=False)
                py_logging.info("cort_think_details: fallback result generated successfully")
                return {
                    "response": result["response"],
                    "details": yaml_log,
                    "model": DEFAULT_MODEL,
                    "provider": f"{DEFAULT_PROVIDER} (fallback)"
                }
            except Exception as e2:
                py_logging.exception(f"[ERROR] cort_think_details fallback also failed: {e2}")
                return {
                    "error": f"Failed to process request: {str(e)}. Fallback also failed: {str(e2)}"
                }
        else:
            py_logging.error("cort_think_details: API key for OpenAI is missing (cannot fallback)")
            return {
                "error": f"Failed to process request: {str(e)}. API key for OpenAI is missing (cannot fallback)"
            }

@server.tool(
    name="cort.think.details.neweval",
    description="""
    Returns a recursive thinking AI response with full reasoning details (new evaluation prompt version).

    Features:
        - Provides a recursive thinking AI response and the reasoning process/history (YAML format) for the given prompt.

    Parameters:
        prompt (str, required): Input prompt for the AI.
        model (str, optional): LLM model name. If not specified, the default model is used.
            - Recommended (OpenAI): "gpt-4.1-nano"
            - Recommended (OpenRouter): "meta-llama/llama-4-maverick:free"
            - Default: mistralai/mistral-small-3.1-24b-instruct:free
            - Please refer to the official provider list for available models.
        provider (str, optional): API provider name. If not specified, the default provider is used.
            - Allowed: "openai" or "openrouter"
            - Default: openrouter
            - Model availability depends on the provider. Please ensure the correct combination.

    Returns:
        dict: {
            "response": AI response (string),
            "details": Reasoning process/history (YAML string),
            "model": Model name used (string),
            "provider": Provider name used (string)
        }

    Notes:
        - If model/provider is omitted, omit the parameter entirely.
        - Passing null or empty string may cause API errors.
        - For fallback behavior on API errors, see the "Parameter Specification and Fallback Handling" section in README.md.
    """
)
async def cort_think_details_neweval(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")],
    model: Annotated[str | None, Field(description="LLM model name to use.\n- Recommended (OpenAI): 'gpt-4.1-nano'\n- Recommended (OpenRouter): 'meta-llama/llama-4-maverick:free'\n- Default: mistralai/mistral-small-3.1-24b-instruct:free\nRefer to the official provider list for available models. If not specified, the default model will be used automatically.")]=None,
    provider: Annotated[str | None, Field(description="API provider name to use.\n- Allowed: 'openai' or 'openrouter'\n- Default: openrouter\nModel availability depends on the provider. Please ensure the correct combination. If not specified, the default provider will be used automatically.")]=None
):
    resolved_model, resolved_provider, api_key = resolve_model_and_provider({"model": model, "provider": provider})
    py_logging.info(f"cort_think_details_neweval called: prompt={prompt} model={resolved_model} provider={resolved_provider}")
    if not prompt:
        py_logging.warning("cort_think_details_neweval: prompt is required")
        return {
            "error": "prompt is required"
        }
    try:
        chat = EnhancedRecursiveThinkingChat(api_key=api_key, model=resolved_model, provider=resolved_provider)
        result = chat.think(prompt, details=True, neweval=True)
        yaml_log = yaml.safe_dump({
            "thinking_rounds": result.get("thinking_rounds"),
            "thinking_history": result.get("thinking_history")
        }, allow_unicode=True, sort_keys=False)
        py_logging.info("cort_think_details_neweval: result generated successfully")
        return {
            "response": result["response"],
            "details": yaml_log,
            "model": resolved_model,
            "provider": resolved_provider
        }
    except Exception as e:
        py_logging.exception(f"[ERROR] cort_think_details_neweval failed: {e}")
        fallback_api_key = get_api_key(DEFAULT_PROVIDER)
        if fallback_api_key:
            try:
                chat = EnhancedRecursiveThinkingChat(api_key=fallback_api_key, model=DEFAULT_MODEL, provider=DEFAULT_PROVIDER)
                result = chat.think(prompt, details=True)
                yaml_log = yaml.safe_dump({
                    "thinking_rounds": result.get("thinking_rounds"),
                    "thinking_history": result.get("thinking_history")
                }, allow_unicode=True, sort_keys=False)
                py_logging.info("cort_think_details_neweval: fallback result generated successfully")
                return {
                    "response": result["response"],
                    "details": yaml_log,
                    "model": DEFAULT_MODEL,
                    "provider": f"{DEFAULT_PROVIDER} (fallback)"
                }
            except Exception as e2:
                py_logging.exception(f"[ERROR] cort_think_details_neweval fallback also failed: {e2}")
                return {
                    "error": f"Failed to process request: {str(e)}. Fallback also failed: {str(e2)}"
                }
        else:
            py_logging.error("cort_think_details_neweval: API key for OpenAI is missing (cannot fallback)")
            return {
                "error": f"Failed to process request: {str(e)}. API key for OpenAI is missing (cannot fallback)"
            }

# --- Mixed LLM List Definition ---
MIXED_LLM_LIST = [
    {"provider": "openai", "model": "gpt-4.1-nano"},
    {"provider": "openrouter", "model": "meta-llama/llama-4-scout:free"},
    {"provider": "openrouter", "model": "google/gemini-2.0-flash-exp:free"},
    {"provider": "openrouter", "model": "mistralai/mistral-small-3.1-24b-instruct:free"},
    {"provider": "openrouter", "model": "meta-llama/llama-3.2-3b-instruct:free"},
    {"provider": "openrouter", "model": "thudm/glm-4-9b:free"},
]

def get_available_mixed_llms():
    """Return only LLMs with valid API keys"""
    available = []
    for entry in MIXED_LLM_LIST:
        api_key = get_api_key(entry["provider"])
        if api_key:
            available.append({**entry, "api_key": api_key})
    return available

import random
from typing import Dict, Any

def generate_with_mixed_llm(prompt: str, details: bool = False, neweval: bool = False) -> Dict[str, Any]:
    available_llms = get_available_mixed_llms()
    if not prompt:
        py_logging.warning("mixed_llm: prompt is required")
        return {"error": "prompt is required"}
    if not available_llms:
        py_logging.error("mixed_llm: No available LLMs (API key missing)")
        return {"error": "No available LLMs (API key missing)"}
 
    # --- Number of rounds and alternatives are determined by AI based on existing logic ---
    # First, randomly select a base LLM
    base_llm = random.choice(available_llms)
    chat = EnhancedRecursiveThinkingChat(api_key=base_llm["api_key"], model=base_llm["model"], provider=base_llm["provider"])
    # Generate base response (initial)
    thinking_rounds = chat._determine_thinking_rounds(prompt)
    py_logging.info("\n=== GENERATING INITIAL RESPONSE ===")
    py_logging.info(f"Base LLM: provider={base_llm['provider']}, model={base_llm['model']}, rounds={thinking_rounds}")
    base_response = chat._call_api([{"role": "user", "content": prompt}], temperature=0.7, stream=False)
    # --- base_response contains only AI response (similar to simple mode) ---
    # If API response is a dict or structure, extract only content key; otherwise, use as is
    if isinstance(base_response, dict) and "content" in base_response:
        current_best = base_response["content"]
    else:
        current_best = base_response
    py_logging.info("=" * 50)
    thinking_history = [{
        "round": 0,
        "llm_prompt": prompt,
        "llm_response": base_response,
        "response": base_response,
        "alternatives": [],
        "selected": -1,
        "explanation": "Initial base response",
        "provider": base_llm["provider"],
        "model": base_llm["model"]
    }]
    # Generate alternatives for each round
    # Use the same logic as EnhancedRecursiveThinkingChat.think (num_alternatives)
    num_alternatives = 3
    if hasattr(chat, 'num_alternatives'):
        num_alternatives = chat.num_alternatives
    for r in range(thinking_rounds):
        py_logging.info(f"\n=== ROUND {r+1}/{thinking_rounds} ===")
        alternatives = []
        alt_llm_info = []
        alt_llm_responses = []
        alt_llm_prompts = []
        for i in range(num_alternatives):
            py_logging.info(f"\n✨ ALTERNATIVE {i+1} ✨")
            alt_llm = random.choice(available_llms)
            alt_prompt = f"""Original message: {prompt}\n\nCurrent response: {current_best}\n\nGenerate an alternative response that might be better. Be creative and consider different approaches.\nAlternative response:"""
            alt_messages = [{"role": "user", "content": alt_prompt}]
            alt_chat = EnhancedRecursiveThinkingChat(api_key=alt_llm["api_key"], model=alt_llm["model"], provider=alt_llm["provider"])
            alt_response = alt_chat._call_api(alt_messages, temperature=0.7 + i * 0.1, stream=False)
            # --- alt_response also contains only AI response (similar to simple mode) ---
            if isinstance(alt_response, dict) and "content" in alt_response:
                alt_response_text = alt_response["content"]
            else:
                alt_response_text = alt_response
            py_logging.info(f"Alternative {i+1}: provider={alt_llm['provider']}, model={alt_llm['model']}")
            alternatives.append({
                "response": alt_response_text,
                "provider": alt_llm["provider"],
                "model": alt_llm["model"]
            })
            alt_llm_info.append({"provider": alt_llm["provider"], "model": alt_llm["model"]})
            alt_llm_responses.append(alt_response)
            alt_llm_prompts.append(alt_prompt)
        # Evaluation is performed by base LLM (following current CoRT practice)
        py_logging.info("\n=== EVALUATING RESPONSES ===")
        alts_text = "\n".join([f"{i+1}. {alt['response']}" for i, alt in enumerate(alternatives)])
        # Evaluation prompt is centrally managed on AI core side
        eval_prompt = chat._build_eval_prompt(prompt, current_best, [alt['response'] for alt in alternatives], neweval=neweval)
        eval_messages = [{"role": "user", "content": eval_prompt}]
        evaluation = chat._call_api(eval_messages, temperature=0.2, stream=False)
        py_logging.info("=" * 50)
 
        lines = [line.strip() for line in evaluation.split('\n') if line.strip()]
        choice = 'current'
        explanation_text = "No explanation provided"
        if lines:
            first_line = lines[0].lower()
            if 'current' in first_line:
                choice = 'current'
            else:
                for char in first_line:
                    if char.isdigit():
                        choice = char
                        break
            if len(lines) > 1:
                explanation_text = ' '.join(lines[1:])
        if choice == 'current':
            selected_response = current_best
            selected_idx = -1
            py_logging.info(f"\n    ✓ Kept current response: {explanation_text}")
        else:
            try:
                idx = int(choice) - 1
                if 0 <= idx < len(alternatives):
                    selected_response = alternatives[idx]["response"]
                    selected_idx = idx
                    py_logging.info(f"\n    ✓ Selected alternative {idx+1}: {explanation_text}")
                else:
                    selected_response = current_best
                    selected_idx = -1
                    py_logging.info(f"\n    ✓ Invalid selection, keeping current response")
            except Exception:
                selected_response = current_best
                selected_idx = -1
                py_logging.info(f"\n    ✓ Could not parse selection, keeping current response")
        # Record the selected provider/model
        if selected_idx != -1 and 0 <= selected_idx < len(alternatives):
            sel_provider = alternatives[selected_idx]["provider"]
            sel_model = alternatives[selected_idx]["model"]
        else:
            # current_best is either base_llm or previous best
            # Pick from the last thinking_history (if not, use base_llm)
            if thinking_history:
                sel_provider = thinking_history[-1].get("provider", base_llm["provider"])
                sel_model = thinking_history[-1].get("model", base_llm["model"])
            else:
                sel_provider = base_llm["provider"]
                sel_model = base_llm["model"]
        thinking_history.append({
            "round": r + 1,
            "llm_prompt": alt_llm_prompts,
            "llm_response": alt_llm_responses,
            "response": selected_response,
            "alternatives": alternatives,
            "selected": selected_idx,
            "explanation": explanation_text,
            "alternatives_llm": alt_llm_info,
            "provider": sel_provider,
            "model": sel_model
        })
        current_best = selected_response
    py_logging.info("\n" + "=" * 50)
    py_logging.info("🎯 FINAL RESPONSE SELECTED")
    py_logging.info("=" * 50)
    result = {"response": current_best}
    # Regardless of details, always return minimal meta information
    result["thinking_rounds"] = thinking_rounds
    result["thinking_history"] = thinking_history
    # Always store the provider/model that generated the final response in best (for simple mode)
    last_provider = None
    last_model = None
    if thinking_history and isinstance(thinking_history[-1], dict):
        last_provider = thinking_history[-1].get("provider")
        last_model = thinking_history[-1].get("model")
    # Prevent null values just in case
    if not last_provider or not last_model:
        # Get from the last alternatives (if options exist)
        last_alts = thinking_history[-1].get("alternatives", [])
        if last_alts and isinstance(last_alts, list):
            last_alt = last_alts[-1]
            last_provider = last_provider or last_alt.get("provider")
            last_model = last_model or last_alt.get("model")
    # If still not found, use base_llm
    if not last_provider:
        last_provider = base_llm["provider"]
    if not last_model:
        last_model = base_llm["model"]
    result["best"] = {
        "response": current_best,
        "provider": last_provider,
        "model": last_model
    }
    if details:
        # Additional information only in details mode
        result["alternatives"] = thinking_history[-1]["alternatives"] if thinking_history else []
    return result

# --- MCP Tool Definitions ---
from typing import Annotated
from pydantic import Field

@server.tool(
    name="cort.think.simple_mixed_llm",
    description="Generate recursive thinking AI response using a different LLM (provider/model) for each alternative. No history/details output. Parameters: prompt (str, required). model/provider cannot be specified (randomly selected internally). Provider/model info for each alternative is always logged and included in the output.",
)
async def cort_think_simple_mixed_llm(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")]
):
    result = generate_with_mixed_llm(prompt, details=False)
    # 必要な情報のみ抽出
    response = result.get("response")
    best = result.get("best")
    return {
        "response": response,
        "model": best.get("model"),
        "provider": best.get("provider")
    }

@server.tool(
    name="cort.think.simple_mixed_llm.neweval",
    description="""
    Generate recursive thinking AI response using a different LLM (provider/model) for each alternative. No history/details output. (new evaluation prompt version)

    Parameters:
        prompt (str, required): Input prompt for the AI (required).
        model/provider cannot be specified (randomly selected internally)。
        Provider/model info for each alternative is always logged and included in the output.

    Returns:
        dict: {
            "response": AI response (string),
            "provider": provider name used (string),
            "model": model name used (string)
        }
    """
)
async def cort_think_simple_mixed_llm_neweval(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")]
):
    result = generate_with_mixed_llm(prompt, details=False, neweval=True)
    # neweval専用プロンプトで評価するために、details=False, neweval=Trueでthinkを呼び出す必要がある場合はここで明示
    response = result.get("response")
    best = result.get("best")
    return {
        "response": response,
        "model": best.get("model"),
        "provider": best.get("provider")
    }

@server.tool(
    name="cort.think.details_mixed_llm",
    description="Generate recursive thinking AI response with full history, using a different LLM (provider/model) for each alternative. Parameters: prompt (str, required). model/provider cannot be specified (randomly selected internally). Provider/model info for each alternative is always logged and included in the output and history.",
)
async def cort_think_details_mixed_llm(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")]
):
    result = generate_with_mixed_llm(prompt, details=True)
    import yaml
    if "thinking_rounds" in result and "thinking_history" in result:
        result["details"] = yaml.safe_dump({
            "thinking_rounds": result["thinking_rounds"],
            "thinking_history": result["thinking_history"]
        }, allow_unicode=True, sort_keys=False)
    return result

@server.tool(
    name="cort.think.details_mixed_llm.neweval",
    description="""
    Generate recursive thinking AI response with full history, using a different LLM (provider/model) for each alternative. (new evaluation prompt version)

    Parameters:
        prompt (str, required): Input prompt for the AI (required).
        model/provider cannot be specified (randomly selected internally).
        Provider/model info for each alternative is always logged and included in the output and history.

    Returns:
        dict: {
            "response": AI response (string),
            "details": YAML-formatted thinking history (string),
            "thinking_rounds": int,
            "thinking_history": list,
            "best": dict, # Information about the LLM that generated the best/final response
            "alternatives": list (only when details=True) # List of alternative responses considered in the final round
        }
    """
)
async def cort_think_details_mixed_llm_neweval(
    prompt: Annotated[str, Field(description="Input prompt for the AI (required)")]
):
    result = generate_with_mixed_llm(prompt, details=True, neweval=True)
    import yaml
    if "thinking_rounds" in result and "thinking_history" in result:
        result["details"] = yaml.safe_dump({
            "thinking_rounds": result["thinking_rounds"],
            "thinking_history": result["thinking_history"]
        }, allow_unicode=True, sort_keys=False)
    return result

# Tools are registered with decorators

def initialize_and_run_server():
    # Initialize and run the MCP server.
    # Logging should be configured by setup_logging by now.
    # We can get the logger instance.
    logger = py_logging.getLogger("cort-mcp-server")
    if not logger.handlers and py_logging.getLogger().hasHandlers(): # Check if specific has no handlers but root does
        logger = py_logging.getLogger() # Fallback to root if specific has no handlers (and propagate is true)
        logger.info("cort-mcp server starting... (using root logger for this message in initialize_and_run_server)")
    else:
        logger.info("cort-mcp server starting... (using 'cort-mcp-server' logger in initialize_and_run_server)")

    # Run the MCP server
    server.run()

def main():
    parser = argparse.ArgumentParser(description="Chain-of-Recursive-Thoughts MCP Server/CLI")
    parser.add_argument("--log", choices=["on", "off"], required=True, help="Enable or disable logging (on/off)")
    parser.add_argument("--logfile", type=str, default=None, help="Absolute path to log file (required if --log=on)")
 
    args = parser.parse_args()

    print(f"[DEBUG_MAIN] Parsed arguments: log='{args.log}', logfile='{args.logfile}'", file=sys.stderr)

    if args.log == "on" and not args.logfile:
        print("[FATAL_MAIN] --logfile is required when --log=on", file=sys.stderr)
        sys.exit(1)
    if args.log == "on" and args.logfile and not os.path.isabs(args.logfile): # Check if logfile is not None
        print(f"[FATAL_MAIN] --logfile must be an absolute path when --log=on. Received: '{args.logfile}'", file=sys.stderr)
        sys.exit(1)
    
    # Call setup_logging to configure logging based on arguments.
    print(f"[DEBUG_MAIN] Calling setup_logging with log='{args.log}', logfile='{args.logfile}'", file=sys.stderr)
    logger = setup_logging(args.log, args.logfile)
    print(f"[DEBUG_MAIN] setup_logging returned: {logger}", file=sys.stderr)

    if logger: # If setup_logging returned a logger instance (i.e., log was 'on')
        logger.info("cort-mcp main() started, using 'cort-mcp-server' logger.")
        # Test root logger as well, if specific logger is different
        if logger is not py_logging.getLogger():
             py_logging.info("cort-mcp main() started, test message via root logger.")
    elif args.log == "on": # Should not happen if setup_logging exits on error
        print("[ERROR_MAIN] Logger was not configured by setup_logging despite --log=on. Check stderr for setup_logging messages.", file=sys.stderr)
    else: # log == "off"
        print("[INFO_MAIN] Logging is off. No logs will be generated by the application.", file=sys.stderr)

    try:
        if logger:
            logger.info("Server mode: waiting for MCP stdio requests...")
        elif args.log == "on": # Log was on, but logger is None (error in setup_logging)
            print("[INFO_MAIN] Server mode: waiting for MCP stdio requests... (logger not fully available)", file=sys.stderr)
        else: # log == "off"
            print("[INFO_MAIN] Server mode: waiting for MCP stdio requests... (logging is off)", file=sys.stderr)

        # Start the server using FastMCP
        initialize_and_run_server()
    except Exception as e:
        if logger:
            logger.exception(f"[ERROR_MAIN] main() unhandled exception: {e}")
        else:
            # Fallback if logger is not available
            print(f"[FATAL_ERROR_MAIN] main() unhandled exception: {e}", file=sys.stderr)
            traceback.print_exc(file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
