"""
Pre-flight validation functions for config.yaml validation.

This module provides standalone validation functions that can be used
to validate configuration files without requiring a full sync or Veza.
"""

import importlib
import logging

from pydantic import ValidationError

from oaa.settings import Config

logger = logging.getLogger(__name__)


def validate_config_structure(config_file):
    """Validate the config.yaml structure using Pydantic.

    :param config_file: Path to the config.yaml file
    :returns: Tuple of (is_valid, errors) where errors is a list of formatted error messages
    """
    errors = []

    try:
        Config.reset()
        Config.update(config_file=config_file)

        if Config._CONFIG:
            return True, []
        else:
            return False, ["Configuration failed to load"]

    except ValidationError as err:
        for e in err.errors():
            loc = (
                ".".join(str(loc_item) for loc_item in e["loc"]) if e["loc"] else "root"
            )  # noqa: E741
            msg = f"  - {loc}: {e['msg']}"
            errors.append(msg)
        return False, errors
    except Exception as err:
        return False, [str(err)]


def validate_connection_modules(config):
    """Validate that custom connection modules can be imported.

    :param config: Config object with connections
    :returns: Tuple of (is_valid, messages) where messages includes success/failure info
    """
    messages = []
    all_valid = True

    if not hasattr(config, "connections") or not config.connections:
        messages.append("No connections defined in config")
        return True, messages

    for name, conn in config.connections.items():
        if hasattr(conn, "custom_module") and conn.custom_module:
            module_import_paths = [
                conn.custom_module,
                f"oaa.modules.{conn.custom_module}",
            ]

            imported = False
            for module_path in module_import_paths:
                try:
                    importlib.import_module(module_path)
                    messages.append(
                        f'✅ Connection "{name}": module "{module_path}" imported successfully'
                    )
                    imported = True
                    break
                except ModuleNotFoundError:
                    continue
                except Exception as exc:
                    messages.append(
                        f'❌ Connection "{name}": error importing "{module_path}": {exc}'
                    )
                    all_valid = False
                    imported = True
                    break

            if not imported:
                messages.append(
                    f'❌ Connection "{name}": could not find module "{conn.custom_module}" '
                    f"(tried: {module_import_paths})"
                )
                all_valid = False

    return all_valid, messages


def test_connectivity(config, test_all=False):
    """Test connectivity to data sources defined in connections.

    :param config: Config object with connections
    :param test_all: If True, test all connections. If False, only test critical ones
    :returns: Tuple of (is_valid, messages) where messages includes success/failure info
    """
    messages = []
    all_valid = True

    if not hasattr(config, "connections") or not config.connections:
        messages.append("No connections defined in config")
        return True, messages

    for name, conn in config.connections.items():
        conn_type = getattr(conn, "connection_type", None)

        if conn_type == "db":
            messages.append(f'Testing DB connection "{name}"...')
            try:
                if hasattr(conn, "_get_connection"):
                    connection = conn._get_connection()
                    if connection:
                        messages.append(
                            f'✅ DB connection "{name}": connected successfully'
                        )
                        connection.close()
                    else:
                        messages.append(f'❌ DB connection "{name}": failed to connect')
                        all_valid = False
            except Exception as exc:
                messages.append(f'❌ DB connection "{name}": {exc}')
                all_valid = False

        elif conn_type in ("api", "veza_api"):
            messages.append(
                f'API connection "{name}": connectivity test not implemented '
                "(would require making actual API call)"
            )

        elif conn_type == "custom":
            messages.append(
                f'Custom connection "{name}": connectivity test not implemented '
                "(would require calling custom module fetch)"
            )

        elif conn_type == "csv":
            messages.append(f'CSV connection "{name}": checking file exists...')
            csv_path = getattr(conn, "csv_filepath", None)
            if csv_path:
                import os

                if os.path.exists(csv_path):
                    messages.append(f'✅ CSV file for connection "{name}": exists')
                else:
                    messages.append(
                        f'❌ CSV file for connection "{name}": file not found at {csv_path}'
                    )
                    all_valid = False

    return all_valid, messages


def run_validation_preflights(runner):
    """Run preflight checks suitable for validation mode.

    This runs the standard preflights but handles the case where
    config may not be fully loaded or Veza connection is not available.

    :param runner: CustomAppRunner instance
    :returns: Tuple of (is_valid, messages)
    """
    from oaa.hooks.preflight_checks import preflights

    messages = []
    all_valid = True

    for pf in preflights:
        pf_name = pf.__name__
        logger.debug(f"Running preflight: {pf_name}")

        try:
            result = pf(runner)

            if result:
                for issue in result:
                    messages.append(f"❌ {pf_name}: {issue}")
                    all_valid = False
            else:
                messages.append(f"✅ {pf_name}: passed")

        except Exception as exc:
            messages.append(f"⚠️  {pf_name}: error running check - {exc}")
            logger.debug(f"Preflight {pf_name} error: {exc}")

    return all_valid, messages


def validate_config(config_file, test_connectivity=False):
    """Main validation function that runs all validation steps.

    :param config_file: Path to the config.yaml file
    :param test_connectivity: Whether to test actual connectivity to data sources
    :returns: Tuple of (is_valid, all_messages) where all_messages is a combined list
    """
    all_messages = []
    all_valid = True

    all_messages.append("=" * 50)
    all_messages.append("STEP 1: Validating config structure...")
    all_messages.append("=" * 50)

    is_valid, errors = validate_config_structure(config_file)
    if not is_valid:
        all_valid = False
        all_messages.extend(errors)
        return all_valid, all_messages

    all_messages.append("✅ Config structure is valid")

    config = Config._CONFIG

    all_messages.append("")
    all_messages.append("=" * 50)
    all_messages.append("STEP 2: Validating connection modules...")
    all_messages.append("=" * 50)

    is_valid, messages = validate_connection_modules(config)
    if not is_valid:
        all_valid = False
    all_messages.extend(messages)

    all_messages.append("")
    all_messages.append("=" * 50)
    all_messages.append("STEP 3: Running preflight checks...")
    all_messages.append("=" * 50)

    from oaa.app_runners.custom_app import CustomAppRunner

    try:
        runner = CustomAppRunner(config_file_yaml=config_file)
        is_valid, messages = run_validation_preflights(runner)
        if not is_valid:
            all_valid = False
        all_messages.extend(messages)
    except Exception as exc:
        all_messages.append(f"⚠️  Could not run preflight checks: {exc}")

    if test_connectivity:
        all_messages.append("")
        all_messages.append("=" * 50)
        all_messages.append("STEP 4: Testing connectivity (per user request)...")
        all_messages.append("=" * 50)

        is_valid, messages = test_connectivity(config, test_all=True)
        if not is_valid:
            all_valid = False
        all_messages.extend(messages)

    all_messages.append("")
    all_messages.append("=" * 50)
    if all_valid:
        all_messages.append("✅ VALIDATION PASSED - Configuration appears ready")
    else:
        all_messages.append("❌ VALIDATION FAILED - Please review errors above")
    all_messages.append("=" * 50)

    return all_valid, all_messages
