import os
import platform
import subprocess
import sys
import traceback
import urllib.parse
import webbrowser

from aider import __version__
from aider.urls import github_issues
from aider.versioncheck import VERSION_CHECK_FNAME

# Global variable to store resolved args data for error reporting
resolved_args_data = None

FENCE = "`" * 3


def get_python_info():
    implementation = platform.python_implementation()
    is_venv = sys.prefix != sys.base_prefix
    return (
        f"Python implementation: {implementation}\nVirtual environment:"
        f" {'Yes' if is_venv else 'No'}"
    )


def get_os_info():
    return f"OS: {platform.system()} {platform.release()} ({platform.architecture()[0]})"


def get_git_info():
    try:
        git_version = subprocess.check_output(["git", "--version"]).decode().strip()
        return f"Git version: {git_version}"
    except Exception:
        return "Git information unavailable"


def format_args_for_reporting(args):
    """
    Format args data for error reporting, removing sensitive keys and collapsing MCP servers.
    """
    if not args:
        return "No args data available"

    # Create a copy of the args namespace as a dictionary
    args_dict = vars(args).copy()

    # Remove any keys containing "key" (case insensitive)
    keys_to_remove = [key for key in args_dict.keys() if "key" in key.lower()]
    for key in keys_to_remove:
        args_dict.pop(key, None)

    # Handle mcp_servers - collapse into just a list of server names
    if "mcp_servers" in args_dict:
        mcp_servers = args_dict["mcp_servers"]
        if isinstance(mcp_servers, str):
            try:
                import json

                config = json.loads(mcp_servers)
                if "mcpServers" in config:
                    server_names = list(config["mcpServers"].keys())
                    args_dict["mcp_servers"] = server_names
            except (json.JSONDecodeError, AttributeError):
                # If parsing fails, keep the original value
                pass

    # Format the output line by line
    lines = ["Configuration:"]
    for key, value in sorted(args_dict.items()):
        lines.append(f"{key}: {value}")

    return "\n".join(lines)


def get_args_error_data():
    global resolved_args_data
    return resolved_args_data


def set_args_error_data(args):
    global resolved_args_data
    resolved_args_data = args


def report_github_issue(issue_text, title=None, confirm=True):
    """
    Compose a URL to open a new GitHub issue with the given text prefilled,
    and attempt to launch it in the default web browser.

    :param issue_text: The text of the issue to file
    :param title: The title of the issue (optional)
    :param confirm: Whether to ask for confirmation before opening the browser (default: True)
    :return: None
    """
    version_info = f"Aider version: {__version__}\n"
    python_version = f"Python version: {sys.version.split()[0]}\n"
    platform_info = f"Platform: {platform.platform()}\n"
    python_info = get_python_info() + "\n"
    os_info = get_os_info() + "\n"
    git_info = get_git_info() + "\n"
    args_info = format_args_for_reporting(get_args_error_data()) + "\n"

    system_info = (
        version_info
        + python_version
        + platform_info
        + python_info
        + os_info
        + git_info
        + "\n"
        + args_info
        + "\n"
    )

    issue_text = system_info + issue_text
    params = {"body": issue_text}
    if title is None:
        title = "Bug report"
    params["title"] = title
    issue_url = f"{github_issues}?{urllib.parse.urlencode(params)}"

    if confirm:
        print(f"\n# {title}\n")
        print(issue_text.strip())
        print()
        print("Please consider reporting this bug to help improve aider!")
        prompt = "Open a GitHub Issue pre-filled with the above error in your browser? (Y/n) "
        confirmation = input(prompt).strip().lower()

        yes = not confirmation or confirmation.startswith("y")
        if not yes:
            return

    print("Attempting to open the issue URL in your default web browser...")
    try:
        if webbrowser.open(issue_url):
            print("Browser window should be opened.")
    except Exception:
        pass

    if confirm:
        print()
        print()
        print("You can also use this URL to file the GitHub Issue:")
        print()
        print(issue_url)
        print()
        print()


def exception_handler(exc_type, exc_value, exc_traceback):
    # If it's a KeyboardInterrupt, just call the default handler
    if issubclass(exc_type, KeyboardInterrupt):
        return sys.__excepthook__(exc_type, exc_value, exc_traceback)

    # We don't want any more exceptions
    sys.excepthook = None

    # Check if VERSION_CHECK_FNAME exists and delete it if so
    try:
        if VERSION_CHECK_FNAME.exists():
            VERSION_CHECK_FNAME.unlink()
    except Exception:
        pass  # Swallow any errors

    # Format the traceback
    tb_lines = traceback.format_exception(exc_type, exc_value, exc_traceback)

    # Replace full paths with basenames in the traceback
    tb_lines_with_basenames = []
    for line in tb_lines:
        try:
            if "File " in line:
                parts = line.split('"')
                if len(parts) > 1:
                    full_path = parts[1]
                    basename = os.path.basename(full_path)
                    line = line.replace(full_path, basename)
        except Exception:
            pass
        tb_lines_with_basenames.append(line)

    tb_text = "".join(tb_lines_with_basenames)

    # Find the innermost frame
    innermost_tb = exc_traceback
    while innermost_tb.tb_next:
        innermost_tb = innermost_tb.tb_next

    # Get the filename and line number from the innermost frame
    filename = innermost_tb.tb_frame.f_code.co_filename
    line_number = innermost_tb.tb_lineno
    try:
        basename = os.path.basename(filename)
    except Exception:
        basename = filename

    # Get the exception type name
    exception_type = exc_type.__name__

    # Prepare the issue text
    issue_text = f"An uncaught exception occurred:\n\n{FENCE}\n{tb_text}\n{FENCE}"

    # Prepare the title
    title = f"Uncaught {exception_type} in {basename} line {line_number}"

    # Report the issue
    report_github_issue(issue_text, title=title)

    # Call the default exception handler
    sys.__excepthook__(exc_type, exc_value, exc_traceback)


def report_uncaught_exceptions():
    """
    Set up the global exception handler to report uncaught exceptions.
    """
    sys.excepthook = exception_handler


def dummy_function1():
    def dummy_function2():
        def dummy_function3():
            raise ValueError("boo")

        dummy_function3()

    dummy_function2()


def main():
    report_uncaught_exceptions()

    dummy_function1()

    title = None
    if len(sys.argv) > 2:
        # Use the first command-line argument as the title and the second as the issue text
        title = sys.argv[1]
        issue_text = sys.argv[2]
    elif len(sys.argv) > 1:
        # Use the first command-line argument as the issue text
        issue_text = sys.argv[1]
    else:
        # Read from stdin if no argument is provided
        print("Enter the issue title (optional, press Enter to skip):")
        title = input().strip()
        if not title:
            title = None
        print("Enter the issue text (Ctrl+D to finish):")
        issue_text = sys.stdin.read().strip()

    report_github_issue(issue_text, title)


if __name__ == "__main__":
    main()
