#!/usr/bin/env python3
# Copyright (c) CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
#

import re
import signal
import sys
from dataclasses import dataclass

from botocore.exceptions import ClientError, NoCredentialsError, ProfileNotFound
from docopt import docopt
from pydantic import ValidationError
from rich.console import Console
from rich.panel import Panel
from rich.pretty import pprint
from rich.text import Text
from rich.traceback import install

# Import version from src package which handles fallback if needed
from src import __version__
from src.features import (
    auth,
    connections,
    costformation,
    czrns,
    dashboard,
    documents_v4,
    info,
    organizations,
    quicksight,
    system,
    views,
)
from src.features.connections import shell
from src.features.organizations import get_organization_data
from src.settings import LATEST_VERSION, Settings, get_formated_error_messages
from src.utils.aws import get_aws_session
from src.utils.console import eprint
from src.utils.system import VersionInfo, cli_version_info
from src.utils.uv_config import auto_fix_uv_config_if_needed
from src.utils.validation import looks_like_an_organization_id

# Constants
CLI_DOC = """CloudZero Operations - Internal tool for maintaining the CloudZero platform

Overview:
    Command line options are defined one of three ways:
    - Required     : All explicit options are required (no brackets)
    - One required : One or more options within () are required
    - Optional     : Options within [] are optional

Usage:
    czops org list [<ID-or-NAME> | --all | --age <DAYS> | --type <TYPE>]  [--raw] [--spend] [-o <FILE>]
    czops org refresh <ORG-ID>
    czops connection list [<ORG-ID-or-NAME>...]  [--raw] [--spend] [-o <FILE>]
    czops (org | connection) info <ID-or-NAME> [--json]
    czops (org | connection) resource-collection (enable | disable | status) <ID-or-NAME>
    czops (org | connection) (disable | enable) <ID-or-NAME>
    czops (org | connection) healthcheck <ID-or-NAME> [--raw | --detailed] [--all] [--no-batch] [-o <FILE>]
    czops org tags <ID-or-NAME> [-o <FILE>]
    czops org auto-link (enable | disable | status | ignore) <ID-or-NAME> [--role-name <ROLE-NAME>] [--ignore-list <comma seperated AWS account list>]
    czops connection reconfigure <ID> [--billing-enable | --billing-disable | --billing-cur <CUR-NAME>] [--force]
    czops anomalies (get [-o <FILE>] | update --file <FILE> [--dryrun] [--quiet] [--raw])
    czops documents (list <ORG-ID> | upload <ORG-ID> --file <FILE> | get <ORG-ID> [--dest <DIRECTORY>] | download <ORG-ID> <FILENAME> [--dest <DIRECTORY>] | delete <ORG-ID> --file <FILE>)
    czops dashboard refresh <ORG-ID>
    czops qs list [<ORG-ID>] [-o <FILE>]
    czops qs create-dataset <ORG-ID> --dashboard <NAME> [--params <JSON>]
    czops qs delete-dataset <ORG-ID> --dataset-id <ID>
    czops qs clear-folder <ORG-ID> [--folder-type <TYPE>] [--force]
    czops qs spice-report <ORG-ID> [-o <FILE>]
    czops qs update-datasets <ORG-ID> --dataset-ids <IDS>
    czops app <ID-or-NAME> [--link-only] [--all]
    czops cf (convert_mapping --file <FILE> [-o <FILE>] [--condition-contains] [--normalize] | mapping_template | mapping_example)
    czops views list <ORG-ID>
    czops czrn [perf] <ARN-or-CZRN>
    czops cwm --profile <PROFILE> --czrn <CZRN>
    czops auth (login | logout | test | refresh | userinfo) [--force] [--security]
    czops (-h | --help)
    czops (-v | --version) [--debug | --quick]"""

CLI_DOC_OPTIONS = """

Options:
    General:
        -h, --help                      Show help information.
        -v, --version                   Display version information.
        --debug                         Enable debug mode (default: False).
        --quick                         Quick version display (no remote calls).
        --ignore-version-check          Skip version compatibility check.

    Output and Files:
        -o, --output <FILE>             Output file; auto-generated if omitted.
        --file <FILE>                   Input file for processing.
        --dest <DIRECTORY>              Directory for saving files.

    Filtering:
        <ORG-ID-or-NAME>                CloudZero organization ID or name.
        <ID-or-NAME>                    Org/connection ID or name (fuzzy match).
        <ID>                            CloudZero organization or connection ID.
        --type <TYPE>                   Filter by connection type.
        --age <DAYS>                    Filter connections by age.

    Reconfigure Options:
        --billing-enable                Enable connection as master payer.
        --billing-disable               Disable connection as master payer.
        --billing-cur <CUR-NAME>        Set billing CUR report name.
        --force                         Skip confirmation prompts.

    Authentication:
        --profile <PROFILE>             AWS profile from ~/.aws/credentials.
        --role-type <ROLETYPE>          Specify role type for session.
        --security                      Run security tests with malicious data.
        --show-secrets                  Show full API keys instead of masked values.

    Display Options:
        --all                           Show all connections + unsupported ones.
        --spend                         Show 30-day cloud spend (may be slower).
        --detailed                      Show detailed healthcheck results.
        --json                          Output raw JSON data (info command only).

    Cache:
        --dryrun                        Simulate without making changes.

    Healthcheck Options:
        --no-batch                      Disable batch API calls for healthcheck."""

# Hidden commands that are only available when hidden_features is enabled
CLI_DOC_HIDDEN_COMMANDS = """
    czops shell (--reset | (--connection-id <ID> --profile <PROFILE> [--role-type <ROLETYPE>] [--eval]))
    czops api-schemas [list | show <endpoint> [--all] | export [<endpoint>] | purge --age <DAYS>]
    czops config cur-rules (list | reset)
    czops system [metadata | refresh-cache | health | reset-database] [--raw] [--confirm] [--force]"""

# ORG_OR_CONNECTION_COMMANDS defines the shared commands between org and connection
# Note: 'conn' is supported as a hidden alias for 'connection' (implemented via argv processing)
ORG_OR_CONNECTION_COMMANDS = ["list", "resource-collection", "disable", "enable", "details"]

install(show_locals=False, width=120)

# Initialize rich console for beautiful output
rich_console = Console()


def check_backend_status() -> str:
    """Check if the backend API is reachable using cached SystemMetadataManager."""
    from src.utils.system_metadata import get_system_metadata_manager

    manager = get_system_metadata_manager()
    if manager.is_available():
        return "ready"
    else:
        return "offline, check your Internet connection"


def display_header(version_info: str, email: str, aws_profile_info: str, is_latest: bool, is_ahead: bool, backend_status: str = "ready") -> None:
    """Display a single-line CLI header with separator line showing backend status."""

    # Get user's display name and groups from Okta if authenticated
    user_display = email or "not authenticated"  # Default fallback
    is_l2_support = False  # Default to No
    try:
        from src.auth.simple_auth import get_authenticator

        authenticator = get_authenticator()
        if authenticator.is_authenticated():
            user_info = authenticator.get_cached_userinfo()
            if user_info:
                # Try multiple name fields
                name = user_info.get("name") or f"{user_info.get('given_name', '')} {user_info.get('family_name', '')}".strip()
                if name and name != " " and email:
                    # Use "Name (email)" format if we have the name
                    user_display = f"{name} ({email})"
                elif email:
                    user_display = email

                # Check if user is in L2 support group
                groups = user_info.get("groups", [])
                is_l2_support = "app-czops-l2" in groups
    except Exception:
        # If anything fails, just use email or fallback
        pass

    # Determine version status
    if is_ahead:
        version_status = "dev"
    elif is_latest:
        version_status = "latest"
    else:
        version_status = "update available"

    # Create the single header line
    header_line = Text()
    header_line.append("🚀☁️  CloudZero Operations CLI ", style="bold cyan")
    header_line.append(f"v{__version__}", style="bold bright_green")
    header_line.append(f" ({version_status})", style="dim bright_green" if is_latest or is_ahead else "dim yellow")
    header_line.append(" 👤 ", style="bright_cyan")
    header_line.append(user_display, style="bright_cyan")

    # Add L2 Support status
    l2_status = "Yes" if is_l2_support else "No"
    l2_style = "bright_green" if is_l2_support else "dim"
    header_line.append(" | L2 Support: ", style="dim")
    header_line.append(l2_status, style=l2_style)

    # Display the header line
    rich_console.print(header_line)

    # Create separator line with backend status
    terminal_width = rich_console.size.width
    status_text = f" {backend_status} "
    separator_length = terminal_width - len(status_text) - 1

    separator_line = Text()
    separator_line.append("─" * separator_length, style="dim bright_blue")
    separator_line.append(status_text, style="dim bright_green" if backend_status == "ready" else "dim yellow")
    separator_line.append("─", style="dim bright_blue")

    # Display the separator line
    rich_console.print(separator_line)


@dataclass
class AWSSession:
    session: object | None = None
    profile_info: str = ""


def setup_signal_handlers():
    def signal_handler(_received_signal, _frame):
        print("You pressed Ctrl+C, exiting.")
        sys.exit(0)

    signal.signal(signal.SIGINT, signal_handler)


def run_silent(args: dict) -> bool:
    """
    Determine if CLI should run silent (useful when CLI is producing input that
    will be consumed by other shell utilities
    """
    silent_args = ["--eval", "--reset"]
    return any(args.get(x) for x in silent_args)


def append_default_options_to_commands(input_text: str, options: list[str]) -> str:
    """Appends specified options to every line starting with 'czops' if not already present"""
    updated_lines = []

    for line in input_text.splitlines():
        if re.match(r"^\s*czops\b", line):
            # Only append options that aren't already in the line
            options_to_add = []
            for opt in options:
                if f"[{opt}]" not in line:
                    options_to_add.append(f"[{opt}]")

            if options_to_add:
                line += f" {' '.join(options_to_add)}"
        updated_lines.append(line)

    return "\n".join(updated_lines)


def prepare_command_options(is_help: bool = False, is_hidden: bool = False) -> str:
    """Merges the hidden commands into the base documentation if enabled"""
    if is_hidden:
        if is_help:
            # For help display, add a separator and header, note this will not be valid input for docopt, only display
            doc = f"{CLI_DOC}\n\n    Hidden Commands Enabled\n    ----------------------------------------{CLI_DOC_HIDDEN_COMMANDS}{CLI_DOC_OPTIONS}"
        else:
            # For regular docopt parsing, just append
            doc = f"{CLI_DOC}{CLI_DOC_HIDDEN_COMMANDS}{CLI_DOC_OPTIONS}"
    else:
        doc = f"{CLI_DOC}{CLI_DOC_OPTIONS}"

    # Only add hidden options when parsing commands, not when showing help
    if is_help:
        return doc
    else:
        return append_default_options_to_commands(doc, ["--debug", "--ignore-version-check"])


def get_aws_session_info(profile: str | None, region: str | None) -> AWSSession:
    """Set up AWS session and return session object with profile info"""
    if not profile:
        return AWSSession()

    try:
        session = get_aws_session(profile=profile, region=region)
        return AWSSession(session=session, profile_info=f"| AWS profile: {profile}")

    except NoCredentialsError:
        return AWSSession(profile_info="| AWS profile Error: Bad Credentials")
    except ProfileNotFound:
        eprint(f"ERROR: AWS profile: NOT FOUND\n\nError: AWS profile {profile} not found")
        sys.exit(1)
    except ClientError as error:
        if "AccessDenied" in str(error):
            eprint(
                f"ERROR: AWS profile: ACCESS DENIED\n\nAccess denied for profile {profile}. "
                "If this profile requires MFA, ensure you have added mfa_serial to your AWS CLI"
                " credentials configuration"
            )
            eprint(f"Error: {error}")
        else:
            eprint(f"UNEXPECTED ERROR creating AWS connection\n\nError: {error}")
        sys.exit(1)


def verify_cli_version(arguments: dict, version_command: bool = False) -> VersionInfo | None:
    """Verify CLI version and handle version-related messages using cached metadata

    Args:
        arguments: Command line arguments dict
        version_command: True when called from --version command, False for normal operation

    Returns:
        VersionInfo if successful, None if failed
    """
    try:
        # Use cached version info to avoid duplicate API calls
        version_info = cli_version_info(arguments)

        # For --version command, always show the version status
        if version_command:
            # Show debug info if requested
            if arguments.get("--debug"):
                print("\nChecking version against CloudZero API...")
                print("\nVersion Check Results:")
                print(f"  Current version: {__version__}")
                print(f"  Latest version: {version_info.version}")
                if version_info.ahead and version_info.latest_release:
                    print(f"  Latest release: {version_info.latest_release}")
                print(f"  Is latest: {version_info.latest}")
                print(f"  Is ahead: {version_info.ahead}")

            # Show version status
            if version_info.ahead:
                print(f"\n✨ You are running a development version (v{__version__})")
                print(f"   This version is ahead of the latest release (v{version_info.latest_release})")
                print("   Note: This is an unreleased version and may contain experimental features.")
            elif not version_info.latest:
                print(f"\n⚠️  A newer version ({version_info.version}) is available.")
                print("   Run 'uv tool upgrade cz-ops-cli' to update.")
                print("   (Migrating from pipx? See https://github.com/Cloudzero/cz-ops-cli#migrating-from-pipx-to-uv-tool)")
            else:
                print("\n✅ You are running the latest version.")

        # For normal operation, enforce version requirements
        else:
            if not version_info.latest and not version_info.ahead:
                eprint(f"\n⚠️  Your CZ-Ops CLI version (v{__version__}) is out of date!")
                eprint(f"📦 Latest version available: v{version_info.version}")
                eprint("\n🔧 Please upgrade to continue by running:")
                eprint("   uv tool upgrade cz-ops-cli")
                eprint("   (Migrating from pipx? See https://github.com/Cloudzero/cz-ops-cli#migrating-from-pipx-to-uv-tool)")
                eprint("\n💡 To bypass this check temporarily, use --ignore-version-check")
                sys.exit(1)
            elif version_info.ahead:
                # Show development version notice in header, but don't block
                if arguments.get("--debug"):
                    eprint(f"✨ Running development version v{__version__} (ahead of latest release v{version_info.latest_release})")

        return version_info

    except Exception as e:
        # Handle errors differently based on context
        if version_command:
            if arguments.get("--debug"):
                print(f"\n❌ Error checking version: {e}")
            else:
                print("\n⚠️  Unable to check for updates.")
        else:
            # For normal operation, errors are handled by the system metadata manager
            # so we don't need to show additional warnings here
            pass

        return None


def verify_uv_config(arguments: dict) -> None:
    """Automatically check and fix UV configuration if needed.

    Args:
        arguments: Command line arguments dict
    """
    # Skip check when using --quick option
    if arguments.get("--quick"):
        return

    try:
        auto_fix_uv_config_if_needed()
    except Exception as e:
        # Show errors in debug mode but don't block CLI operation
        if arguments.get("--debug"):
            eprint(f"DEBUG: UV config check failed: {e}")
        # Continue silently in normal mode


def validate_connection_command_id(id_or_name: str, command_name: str) -> bool:
    """
    Validate that the ID provided to a connection command is not an organization ID.

    Connection commands (except 'list') require a connection ID or name, not an org ID.

    Args:
        id_or_name: The ID or name provided by the user
        command_name: Name of the command being executed (for error message)

    Returns:
        bool: True if validation passes, False if it's an org ID

    Side Effects:
        Prints error message and exits if an org ID is detected
    """
    if not id_or_name:
        return True  # Let downstream code handle empty values

    # Check if the input looks like an organization ID (UUID)
    if looks_like_an_organization_id(id_or_name):
        rich_console.print("\n[red]Error: Organization ID provided for connection command[/]\n")
        rich_console.print(f"The ID '[cyan]{id_or_name}[/]' appears to be an [yellow]organization ID[/] (UUID format).")
        rich_console.print(
            f"\nThe '[white]czops connection {command_name}[/]' command requires a [yellow]connection ID or name[/], not an organization ID.\n"
        )

        rich_console.print("[cyan]💡 Did you mean:[/]")
        rich_console.print(f"  • [white]czops connection list {id_or_name}[/] - List connections for an organization")
        rich_console.print(f"  • [white]czops org {command_name} {id_or_name}[/] - Run command on the organization")
        rich_console.print("\n[cyan]💡 To find connection IDs:[/]")
        rich_console.print(f"  • [white]czops connection list {id_or_name}[/] - Show all connections for this organization")
        rich_console.print("  • [white]czops org list[/] - List all organizations\n")

        sys.exit(1)

    return True


def run():
    setup_signal_handlers()

    # Replace 'conn' with 'connection' in the arguments before processing
    # This allows 'conn' to work as an alias without appearing in help
    if len(sys.argv) > 1 and sys.argv[1] == "conn":
        sys.argv[1] = "connection"

    # Load settings
    is_help = (len(sys.argv) == 2 and sys.argv[1] in ["-h", "--help"]) or len(sys.argv) == 1

    try:
        settings = Settings()
    except Exception:  # noqa
        # If settings don't exist or are invalid, create them with defaults
        settings = Settings(version=LATEST_VERSION)
        settings.save()
        print("✅ Created default settings file")
        # Continue execution with new settings

    # Prepare for docopt parsing based on hidden features status
    doc_content = prepare_command_options(is_help, settings.hidden_features)

    if is_help:
        print(doc_content)
        sys.exit(0)

    arguments = docopt(doc_content)

    # Check and auto-fix UV configuration if needed
    # This runs early to ensure UV config is set up for all commands
    verify_uv_config(arguments)

    try:
        settings = Settings()
        if "json" not in settings.source:
            eprint(f"Migrating CZ-OPS Settings from {settings.source} to JSON")
            settings.save()
    except ValidationError as error:
        eprint(f"{error.error_count()} configuration errors detected")
        for msg in get_formated_error_messages(error):
            eprint(f" - {msg}")
        eprint("\nCZ-OPS CLI configuration error. Settings will be recreated with defaults.")
        # Try to recreate with defaults
        try:
            settings = Settings(version=LATEST_VERSION)
            settings.save()
            eprint("✅ Created default settings file")
        except Exception as e:
            eprint(f"❌ Failed to create settings: {e}")
            sys.exit(1)

    if arguments.get("--debug"):
        filtered_args = {k: v for k, v in arguments.items() if v}
        pprint(f"Arguments: {filtered_args}")

    # Handle --version flag
    if arguments.get("--version"):
        # Check if --quick option is used
        if arguments.get("--quick"):
            # Quick version display - no remote calls, just print the version
            print(f"v{__version__}")
            sys.exit(0)

        # Clear local system metadata cache to ensure accurate version info
        from src.utils.system_metadata import get_system_metadata_manager

        manager = get_system_metadata_manager()
        manager.clear_cache()

        # Display beautiful version info
        version_text = Text()
        version_text.append("☁️  CloudZero ", style="bold cyan")
        version_text.append("Operations CLI ", style="bold bright_blue")
        version_text.append(f"v{__version__}", style="bold bright_green")

        rich_console.print(Panel(version_text, border_style="bright_blue", padding=(0, 1), title="🔍 Version Info", title_align="left"))

        verify_cli_version(arguments, version_command=True)
        sys.exit(0)

    # Check version for normal operation (unless --ignore-version-check is used)
    version_info = None
    if not arguments.get("--ignore-version-check"):
        version_info = verify_cli_version(arguments)

    # Use the version info we already fetched, or get it if we skipped the check
    if version_info:
        is_ahead = version_info.ahead
    else:
        # If we skipped the check or it failed, check with cached manager for display
        try:
            from src.utils.system_metadata import get_system_metadata_manager

            manager = get_system_metadata_manager()
            # Try to get cached metadata without triggering new API calls
            manager.get_metadata(arguments)
            is_ahead = False  # Default assumption if we can't determine
        except Exception:
            # If API call fails, assume current version
            is_ahead = False

    aws_session_info = get_aws_session_info(profile=arguments.get("--profile"), region=arguments.get("--region"))

    version_message = f"CloudZero Operations CLI v{__version__} (development version)" if is_ahead else f"CloudZero Operations CLI v{__version__}"

    # Display beautiful header with relaxing colors (unless in silent mode)
    if not run_silent(arguments):
        # Check backend status
        backend_status = check_backend_status()

        # Determine version status
        is_latest_version = version_info.latest if version_info else True
        is_ahead_version = version_info.ahead if version_info else False

        display_header(version_message, settings.email, aws_session_info.profile_info, is_latest_version, is_ahead_version, backend_status)

    # Process organization ID/name for org commands
    # Most commands should search all orgs (enabled and disabled) when looking up by ID
    # Only 'list' command should respect the enabled filter by default
    # For connection list, organization_data is None and will be fetched internally by _fetch_connections if needed
    if arguments.get("org"):
        # Commands that should search all organizations (enabled and disabled)
        # These commands operate on a specific org, so they should find it regardless of enabled status
        search_all_commands = ["info", "enable", "disable", "refresh", "tags", "healthcheck", "auto-link", "resource-collection"]
        if any(arguments.get(cmd) for cmd in search_all_commands):
            # Force --all flag to search all orgs regardless of enabled status
            modified_arguments = arguments.copy()
            modified_arguments["--all"] = True
            organization_data = get_organization_data(arguments.get("<ID-or-NAME>"), modified_arguments)
        else:
            # For 'list' command, respect the --all flag from user input
            organization_data = get_organization_data(arguments.get("<ID-or-NAME>"), arguments)
    else:
        organization_data = None

    if arguments.get("org"):
        if arguments.get("list"):
            organizations.list_orgs(arguments, organization_data)
        elif arguments.get("refresh"):
            organizations.refresh_org(arguments, organization_data)
        elif arguments.get("tags"):
            organizations.list_org_tags(arguments, organization_data)
        elif arguments.get("auto-link"):
            connections.link.functions(arguments, organization_data)
        elif arguments.get("resource-collection"):
            connections.resource_collection.functions(arguments, organization_data)
        elif arguments.get("enable") or arguments.get("disable"):
            organizations.enable_disable(arguments, organization_data)
        elif arguments.get("healthcheck"):
            organizations.org_healthcheck(arguments, organization_data)
        elif arguments.get("info"):
            info.handle_info_command(arguments, organization_data)
        else:
            eprint("Unknown option, please try again or let #cz-tools know we have a bug")

    elif arguments.get("connection"):
        if arguments.get("list"):
            # 'list' command takes org ID, so no validation needed
            connections.list.list_functions(arguments, organization_data)
        elif arguments.get("resource-collection"):
            # Validate that user didn't provide an org ID
            id_or_name = arguments.get("<ID-or-NAME>")
            validate_connection_command_id(id_or_name, "resource-collection")
            print("Resource collection configuration at the connection level is not yet implemented")
        elif arguments.get("disable") or arguments.get("enable"):
            # Validate that user didn't provide an org ID
            id_or_name = arguments.get("<ID-or-NAME>")
            command_name = "enable" if arguments.get("enable") else "disable"
            validate_connection_command_id(id_or_name, command_name)
            connections.enable_disable.functions(arguments, organization_data)
        elif arguments.get("healthcheck"):
            # Validate that user didn't provide an org ID
            id_or_name = arguments.get("<ID-or-NAME>")
            validate_connection_command_id(id_or_name, "healthcheck")
            connections.healthcheck.functions(arguments, organization_data)
        elif arguments.get("info"):
            # Validate that user didn't provide an org ID
            id_or_name = arguments.get("<ID-or-NAME>")
            validate_connection_command_id(id_or_name, "info")
            info.handle_info_command(arguments, organization_data)
        elif arguments.get("reconfigure"):
            # Validate that user didn't provide an org ID
            id_or_name = arguments.get("<ID>")
            validate_connection_command_id(id_or_name, "reconfigure")
            connections.reconfigure.functions(arguments)
        else:
            eprint("Unknown option, please try again or let #cz-tools know we have a bug")

    elif arguments.get("anomalies"):
        # Lazy load anomalies module only when needed
        from src.features import anomalies

        if arguments.get("get"):
            anomalies.get(arguments)
        elif arguments.get("update"):
            anomalies.update(arguments)

    elif arguments.get("views"):
        if arguments.get("list"):
            views.list_views(arguments.get("<ORG-ID>"))

    elif arguments.get("czrn"):
        if arguments.get("<ARN-or-CZRN>").upper().startswith("ARN"):
            czrns.convert_arn(arguments.get("<ARN-or-CZRN>"))
        elif arguments.get("<ARN-or-CZRN>").upper().startswith("CZRN"):
            if arguments.get("perf"):
                czrns.czrn_perf_test(arguments.get("<ARN-or-CZRN>"))
            else:
                czrns.extract_czrn_parts(arguments.get("<ARN-or-CZRN>"))

    elif arguments.get("documents"):
        debug = arguments.get("--debug", False)
        if arguments.get("list"):
            documents_v4.list_documents_for_org(arguments.get("<ORG-ID>"), debug=debug)
        elif arguments.get("upload"):
            documents_v4.upload_document_to_org(arguments.get("<ORG-ID>"), arguments.get("<FILE>"), debug=debug)
        elif arguments.get("get"):
            documents_v4.get_document_from_org(arguments.get("<ORG-ID>"), arguments.get("--dest"), debug=debug)
        elif arguments.get("download"):
            documents_v4.download_document_from_org(arguments.get("<ORG-ID>"), arguments.get("<FILENAME>"), arguments.get("--dest"), debug=debug)
        elif arguments.get("delete"):
            documents_v4.delete_document_from_org(arguments.get("<ORG-ID>"), arguments.get("<FILE>"), debug=debug)

    elif arguments.get("dashboard"):
        if arguments.get("refresh"):
            dashboard.refresh.refresh(arguments.get("<ORG-ID>"))

    elif arguments.get("qs"):
        quicksight.handle_command(arguments)

    elif arguments.get("cwm"):
        # Lazy load cwm module only when needed
        from src.features import cwm

        cwm.get_metrics(aws_session_info.session, arguments)

    elif arguments.get("api-schemas"):
        # Lazy load api_schemas module only when needed
        from src.features import api_schemas

        api_schemas.handle_command(arguments)
    elif arguments.get("app"):
        # Lazy load app module only when needed
        from src.features import app

        app.open_webpage(arguments)

    elif arguments.get("cf"):
        if arguments.get("convert_mapping"):
            costformation.convert_mapping(arguments)
        elif arguments.get("mapping_template"):
            costformation.generate_template()
        elif arguments.get("mapping_example"):
            costformation.generate_example()

    elif arguments.get("shell"):
        shell.create_shell(arguments, aws_session_info)

    elif arguments.get("auth"):
        auth.handle_auth_command(arguments)

    elif arguments.get("config") and arguments.get("cur-rules"):
        # Lazy load cur_rules module only when needed
        from src.features import cur_rules

        cur_rules.functions(arguments)

    elif arguments.get("system"):
        system.handle_command(arguments)

    else:
        eprint("You specified an unsupported or unknown option, please try again or let #cz-tools know we have a bug")
    # print_error_image("Woot")


if __name__ == "__main__":
    """
    Note, this code is never called because of how setup.py is configured, but it's good practice to have this here
    """
    sys.exit(run())
