import logging
import os

from agentflow.core.graph import CompiledGraph
from fastapi import FastAPI
from fastapi.concurrency import asynccontextmanager
from fastapi.responses import ORJSONResponse
from injectq import InjectQ
from injectq.integrations.fastapi import setup_fastapi

# # Prometheus Instrumentator import
# from prometheus_fastapi_instrumentator import Instrumentator
# from tortoise import Tortoise
from agentflow_cli.src.app.core import (
    get_settings,
    init_errors_handler,
    init_logger,
    setup_middleware,
)
from agentflow_cli.src.app.core.config.graph_config import GraphConfig
from agentflow_cli.src.app.loader import attach_all_modules, load_container
from agentflow_cli.src.app.routers import init_routes


logger = logging.getLogger("agentflow_api")

settings = get_settings()
# redis_client = Redis(
#     host=settings.REDIS_HOST,
#     port=settings.REDIS_PORT,
# )

graph_path = os.environ.get("GRAPH_PATH", "agentflow.json")
graph_config = GraphConfig(graph_path)
# Load the container
container: InjectQ = load_container(graph_config.injectq_path) or InjectQ.get_instance()

# Save config instance
container.bind_instance(GraphConfig, graph_config)


async def _cleanup_temp_media_cache() -> None:
    """Run best-effort cleanup of expired temporary media cache entries."""
    try:
        from agentflow.storage.media.temp_cache import TemporaryMediaCache

        checkpointer = container.try_get("checkpointer") or container.try_get("BaseCheckpointer")
        media_store = container.try_get("media_store") or container.try_get("BaseMediaStore")

        if checkpointer is None:
            logger.debug("No checkpointer available, skipping temp media cache cleanup")
            return

        cache = TemporaryMediaCache()
        cleaned = await cache.cleanup(checkpointer, media_store)
        if cleaned:
            logger.info("Cleaned up %d expired temporary media cache entries on startup", cleaned)
        else:
            logger.debug("No expired temporary media cache entries to clean up")
    except Exception as e:
        logger.warning("Failed to clean up temporary media cache on startup: %s", e)


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Load the cache
    # RedisCacheBackend(settings.REDIS_URL)

    graph: CompiledGraph | None = await attach_all_modules(
        graph_config,
        container=container,
    )

    # Clean up expired temporary media cache on startup
    await _cleanup_temp_media_cache()

    # load Store
    # store = load_store(graph_config.store_path)
    # injector.binder.bind(BaseStore, store)

    yield
    # Clean up
    # await close_caches()
    # close all the connections
    if graph:
        # release all the resources
        await graph.aclose()

    # Close rate-limit backend (e.g. Redis connection pool)
    backend = getattr(app.state, "rate_limit_backend", None)
    if backend is not None:
        await backend.close()


app = FastAPI(
    title=settings.APP_NAME,
    version=settings.APP_VERSION,
    debug=settings.MODE == "DEVELOPMENT",
    summary=settings.SUMMARY,
    docs_url=settings.DOCS_PATH if settings.DOCS_PATH else None,
    redoc_url=settings.REDOCS_PATH if settings.REDOCS_PATH else None,
    default_response_class=ORJSONResponse,
    lifespan=lifespan,
    root_path=settings.ROOT_PATH,
)

setup_middleware(app, graph_config=graph_config, container=container)

# attach_injector(app, injector=injector)
setup_fastapi(container=container, app=app)

init_logger(settings.LOG_LEVEL)

# init error handler
init_errors_handler(app)

# init routes
init_routes(app)

# instrumentator = Instrumentator().instrument(app)  # Instrument first
# instrumentator.expose(app)  # Then expose
