"""
NexQuant Quant Loop Factory - Selects appropriate workflow based on available components.

This module is the entry point for the quantitative trading loop.
It automatically selects between:
1. Standard Loop (Open Source) - Factor generation + backtesting
2. Advanced Loop (Local/Closed Source) - Full ML pipeline with portfolio & strategy

The selection is based on:
- Availability of local components (ml_trainer, portfolio_optimizer)
- Number of valid factors (threshold: 5000 for advanced loop)

Usage:
    from rdagent.scenarios.qlib.quant_loop_factory import create_quant_loop

    loop = create_quant_loop(scenario)
    loop.run()
"""

from pathlib import Path
from typing import Optional

from rdagent.log import rdagent_logger as logger


# Threshold for advanced loop activation
ADVANCED_LOOP_FACTOR_THRESHOLD = 5000


def has_local_components() -> bool:
    """
    Check if local (closed source) components are available.

    Returns True if:
    - rdagent/scenarios/qlib/local/ml_trainer.py exists
    - rdagent/scenarios/qlib/local/portfolio_optimizer.py exists
    """
    local_dir = Path(__file__).parent / "local"
    if not local_dir.exists():
        return False

    required_files = [
        "ml_trainer.py",
        "portfolio_optimizer.py",
    ]

    for fname in required_files:
        if not (local_dir / fname).exists():
            return False

    return True


def count_valid_factors() -> int:
    """
    Count the number of valid (successful) factors in results/factors/.

    Returns
    -------
    int
        Number of valid factors
    """
    import json
    from glob import glob

    project_root = Path(__file__).parent.parent.parent.parent
    factors_dir = project_root / "results" / "factors"

    if not factors_dir.exists():
        return 0

    count = 0
    for json_file in glob(str(factors_dir / "*.json")):
        try:
            with open(json_file) as f:
                data = json.load(f)
            if data.get("status") == "success" and data.get("ic") is not None:
                count += 1
        except Exception:
            logger.warning("Failed to load factor file %s", json_file, exc_info=True)
            continue

    return count


def create_quant_loop(scenario) -> "BaseQuantLoop":
    """
    Create the appropriate QuantLoop based on available components.

    Priority:
    1. Advanced Loop (if local components exist AND 5000+ factors)
    2. Standard Loop (always available)

    Parameters
    ----------
    scenario : Scenario
        The trading scenario

    Returns
    -------
    BaseQuantLoop
        The appropriate quant loop instance
    """
    local_available = has_local_components()
    factor_count = count_valid_factors()

    logger.info(
        f"Quant Loop Factory: local_components={local_available}, "
        f"valid_factors={factor_count}, threshold={ADVANCED_LOOP_FACTOR_THRESHOLD}"
    )

    if local_available and factor_count >= ADVANCED_LOOP_FACTOR_THRESHOLD:
        logger.info("Creating AdvancedQuantLoop (ML + Portfolio + Strategy)")
        from rdagent.scenarios.qlib.local.quant_loop_advanced import AdvancedQuantLoop
        return AdvancedQuantLoop(scenario)
    else:
        if not local_available:
            logger.info("Local components not found — using StandardQuantLoop")
        else:
            logger.info(
                f"Only {factor_count}/{ADVANCED_LOOP_FACTOR_THRESHOLD} factors — "
                f"using StandardQuantLoop (need {ADVANCED_LOOP_FACTOR_THRESHOLD - factor_count} more)"
            )

        from rdagent.app.qlib_rd_loop.quant import QuantRDLoop
        return QuantRDLoop


# Base class for type hints
class BaseQuantLoop:
    """Base class for quant loops."""
    pass
