from __future__ import annotations
import traceback
from pydantic import BaseModel, Field  # type: ignore
from typing import (
    Literal,
    get_args,
    List,
    AsyncGenerator,
    TYPE_CHECKING,
    Optional,
    ClassVar,
    Any,
    TypeAlias,
    Dict,
    Tuple,
)
import importlib
import pathlib
import inspect
from prometheus_client import CollectorRegistry  # type: ignore

from . base import Agent
from logger import logger
from models import Candidate

_agents: List[Agent] = []

def get_or_create_agent(agent_type: str, prometheus_collector: CollectorRegistry, user: Optional[Candidate]=None) -> Agent:
    """
    Get or create and append a new agent of the specified type, ensuring only one agent per type exists.

    Args:
        agent_type: The type of agent to create (e.g., 'general', 'candidate_chat', 'image_generation').
        **kwargs: Additional fields required by the specific agent subclass.

    Returns:
        The created agent instance.

    Raises:
        ValueError: If no matching agent type is found or if a agent of this type already exists.
    """
    # Check if a global (non-user) agent with the given agent_type already exists
    if not user:
        for agent in _agents:
            if agent.agent_type == agent_type:
                return agent

    # Find the matching subclass
    for agent_cls in Agent.__subclasses__():
        if agent_cls.model_fields["agent_type"].default == agent_type:
            # Create the agent instance with provided kwargs
            agent = agent_cls(agent_type=agent_type, user=user, prometheus_collector=prometheus_collector)
#            if agent.agent_persist: # If an agent is not set to persist, do not add it to the list
            _agents.append(agent)
            return agent

    raise ValueError(f"No agent class found for agent_type: {agent_type}")

# Type alias for Agent or any subclass
AnyAgent: TypeAlias = Agent  # BaseModel covers Agent and subclasses

# Maps class_name to (module_name, class_name)
class_registry: Dict[str, Tuple[str, str]] = (
    {}
)

__all__ = ['get_or_create_agent']

package_dir = pathlib.Path(__file__).parent
package_name = __name__

for path in package_dir.glob("*.py"):
    if path.name in ("__init__.py", "base.py") or path.name.startswith("_"):
        continue

    module_name = path.stem
    full_module_name = f"{package_name}.{module_name}"

    try:
        module = importlib.import_module(full_module_name)

        # Find all Agent subclasses in the module
        for name, obj in inspect.getmembers(module, inspect.isclass):
            if (
                issubclass(obj, AnyAgent)
                and obj is not AnyAgent
                and obj is not Agent
                and name not in class_registry
            ):
                class_registry[name] = (full_module_name, name)
                globals()[name] = obj
                logger.info(f"Adding agent: {name}")
                __all__.append(name)  # type: ignore
    except ImportError as e:
        logger.error(traceback.format_exc())
        logger.error(f"Error importing {full_module_name}: {e}")
        raise e
    except Exception as e:
        logger.error(traceback.format_exc())
        logger.error(f"Error processing {full_module_name}: {e}")
        raise e
