"""
Main entry point for the data exchange agent application.

This module provides the main function and command-line interface for starting
the data exchange agent server with configurable parameters.
"""

import argparse
import atexit
import os
import signal
import sys
import threading
import time

from data_exchange_agent.cli.argument_parser import create_argument_parser
from data_exchange_agent.container import create_container
from data_exchange_agent.servers.flask_app import FlaskApp
from data_exchange_agent.utils.decorators import print_error_with_message
from shared.telemetry import (
    FEATURE_DATA_MIGRATION,
    MigrationFailureType,
    log_agent_start,
    log_agent_stop,
    log_framework_crash,
    sanitize_error_message,
)


@print_error_with_message(error_message="Error starting the Data Exchange Agent application.")
def _run_server(args: argparse.Namespace) -> None:
    """
    Start the data exchange agent server.

    Args:
        args: Command line arguments

    """
    # Get config path if provided and normalize for cross-platform compatibility
    config_path = getattr(args, "config", None)
    if config_path:
        config_path = os.path.normpath(config_path)

    # Initialize the container
    container = create_container(args, config_path=config_path)

    # Trigger Snowflake connection (and telemetry init) so lifecycle events can be sent
    try:
        container.snowflake_datasource().create_connection()
    except Exception:
        pass

    start_time = time.time()
    _original_excepthook = sys.excepthook

    def _on_exit() -> None:
        duration_ms = (time.time() - start_time) * 1000
        log_agent_stop(
            duration_ms=duration_ms,
            feature=FEATURE_DATA_MIGRATION,
            graceful_shutdown="true",
            uptime_seconds=int(duration_ms / 1000),
        )

    def _on_crash(exc_type: type[BaseException], exc_value: BaseException, exc_tb: object) -> None:
        log_framework_crash(
            failure_type=MigrationFailureType.FRAMEWORK_UNEXPECTED_ERROR,
            error_msg=sanitize_error_message(str(exc_value)),
        )
        _original_excepthook(exc_type, exc_value, exc_tb)

    atexit.register(_on_exit)
    sys.excepthook = _on_crash

    log_agent_start(feature=FEATURE_DATA_MIGRATION)

    if getattr(args, "no_server", False):
        # Worker-only mode: run task handling without HTTP server.
        # Use a threading.Event instead of signal.pause() because
        # signal.pause() returns on ANY signal (including SIGCHLD
        # from child processes like BCP), which would prematurely
        # exit the agent and kill its daemon worker threads.
        task_manager = container.task_manager()
        shutdown_event = threading.Event()

        def _handle_shutdown(signum: int, frame: object) -> None:
            task_manager.stop()
            shutdown_event.set()

        signal.signal(signal.SIGTERM, _handle_shutdown)
        signal.signal(signal.SIGINT, _handle_shutdown)
        task_manager.handle_tasks()
        shutdown_event.wait()
        return

    # Create and start the Flask app
    flask_app = FlaskApp()
    flask_app.create_app()
    flask_app.start_server()


def main() -> None:
    """
    Run the data exchange agent application.

    Supports two modes:
    - test: Verify configuration and connections
    - run (default): Start the agent server

    """
    parser = create_argument_parser()
    args = parser.parse_args()

    # Handle commands
    if args.command == "test":
        from data_exchange_agent.cli import run_connection_test

        sys.exit(run_connection_test(args))
    elif args.command == "run":
        _run_server(args)
    else:
        # Default: run server (backwards compatible)
        _run_server(args)


if __name__ == "__main__":
    main()
