# integration_hub.py
import asyncio
import json
import logging
import os
from datetime import datetime
from typing import Any, Dict, List, Optional

import httpx
import redis.asyncio as aioredis
import tenacity
from qdrant_client import QdrantClient, models
import psycopg
from psycopg_pool import ConnectionPool

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("IntegrationHub")

# Load environment
try:
    from dotenv import load_dotenv
    load_dotenv()
except ImportError:
    logger.warning("dotenv not installed, using system environment variables.")


class IntegrationHub:
    """
    Central hub for integrating various services:
    - Ollama/QwenLong (reasoning)
    - Redis (pub/sub)
    - PostgreSQL (persistent storage)
    - Qdrant (vector embeddings)
    - n8n (workflow automation)
    - External APIs (GHL, Stripe, Telegram)
    """

    DEFAULT_OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434/api/generate")  # Updated default for Ollama
    DEFAULT_REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379")
    DEFAULT_POSTGRES_URL = os.getenv("POSTGRES_URL", "postgresql://user:password@localhost:5432/database")
    DEFAULT_QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6333")
    DEFAULT_QDRANT_API_KEY = os.getenv("QDRANT_API_KEY") # Optional API key

    RATE_LIMIT_MAX_CALLS = int(os.getenv("RATE_LIMIT_MAX_CALLS", "100"))
    RATE_LIMIT_PERIOD = int(os.getenv("RATE_LIMIT_PERIOD", "60"))  # seconds

    def __init__(self):
        self.ollama_url = self.DEFAULT_OLLAMA_URL
        self.redis_url = self.DEFAULT_REDIS_URL
        self.postgres_url = self.DEFAULT_POSTGRES_URL
        self.qdrant_url = self.DEFAULT_QDRANT_URL
        self.qdrant_api_key = self.DEFAULT_QDRANT_API_KEY

        self.ollama_model = os.getenv("AIVA_MODEL", "qwen-long")
        self.timeout = float(os.getenv("AIVA_TIMEOUT", "300"))

        self._redis_client = None
        self._http_client = None
        self._postgres_pool = None
        self._qdrant_client = None

        self._rate_limit_counter = 0
        self._rate_limit_reset = datetime.now()

        logger.info("IntegrationHub initialized.")

    async def connect(self):
        """Establish connections to all services."""
        await self._connect_redis()
        await self._connect_postgres()
        self._connect_qdrant()

    async def close(self):
        """Close all connections."""
        await self._close_redis()
        await self._close_postgres()
        self._close_qdrant()
        if self._http_client and not self._http_client.is_closed:
            await self._http_client.aclose()
        logger.info("IntegrationHub connections closed.")

    # --- Rate Limiting ---

    def _check_rate_limit(self):
        """Check and enforce rate limits."""
        now = datetime.now()
        if now > self._rate_limit_reset:
            self._rate_limit_counter = 0
            self._rate_limit_reset = now + timedelta(seconds=self.RATE_LIMIT_PERIOD)

        if self._rate_limit_counter >= self.RATE_LIMIT_MAX_CALLS:
            raise Exception("Rate limit exceeded.")
        self._rate_limit_counter += 1

    # --- Ollama/QwenLong Integration ---
    async def _get_http_client(self) -> httpx.AsyncClient:
        if self._http_client is None or self._http_client.is_closed:
            self._http_client = httpx.AsyncClient(timeout=self.timeout)
        return self._http_client

    @tenacity.retry(stop=tenacity.stop_after_attempt(3), wait=tenacity.wait_fixed(1))
    async def reason(self, prompt: str, context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        Send a reasoning request to Ollama.
        """
        self._check_rate_limit()

        full_prompt = prompt
        if context:
            context_str = json.dumps(context, indent=2)
            full_prompt = f"Context:\n