"""Functions for validating Rasa projects."""

import sys
from contextlib import contextmanager
from typing import Optional

import structlog
from structlog.testing import capture_logs

from rasa.builder import config
from rasa.builder.exceptions import ValidationError
from rasa.cli.utils import validate_files
from rasa.shared.importers.importer import TrainingDataImporter

structlogger = structlog.get_logger()


@contextmanager
def _mock_sys_exit():
    """Context manager to prevent sys.exit from being called during validation."""
    was_sys_exit_called = {"value": False}

    def sys_exit_mock(code: int = 0):
        was_sys_exit_called["value"] = True

    original_exit = sys.exit
    sys.exit = sys_exit_mock

    try:
        yield was_sys_exit_called
    finally:
        sys.exit = original_exit


async def validate_project(importer: TrainingDataImporter) -> Optional[str]:
    """Validate a Rasa project.

    Args:
        importer: Training data importer with domain, flows, and config

    Returns:
        None if validation passes, error message if validation fails.

    Raises:
        ValidationError: If validation fails
    """
    try:
        with _mock_sys_exit() as exit_tracker:
            with capture_logs() as cap_logs:
                validate_files(
                    fail_on_warnings=config.VALIDATION_FAIL_ON_WARNINGS,
                    max_history=config.VALIDATION_MAX_HISTORY,
                    importer=importer,
                )

            if exit_tracker["value"]:
                error_logs = [
                    log for log in cap_logs if log.get("log_level") != "debug"
                ]
                structlogger.error(
                    "validation.failed.sys_exit",
                    error_logs=error_logs,
                )
                raise ValidationError(
                    "Validation failed with sys.exit", validation_logs=error_logs
                )

            structlogger.info("validation.success")
            return None

    except ValidationError:
        raise
    except Exception as e:
        error_msg = f"Validation failed with exception: {e}"
        structlogger.error(
            "validation.failed.exception",
            error=str(e),
        )
        raise ValidationError(error_msg)
