"""
VSS ClickHouse Client
Handles queries against aggregated_analytics_final table.
"""

import logging
from typing import List, Dict, Any, Tuple, Optional
import clickhouse_connect
from clickhouse_connect.driver.client import Client

from config.settings import ClickHouseConfig, get_settings

logger = logging.getLogger(__name__)


class ClickHouseClient:
    """ClickHouse client for VSS analytics queries."""
    
    def __init__(self, config: Optional[ClickHouseConfig] = None):
        self.config = config or get_settings().clickhouse
        self._client: Optional[Client] = None
    
    @property
    def client(self) -> Client:
        if self._client is None:
            self._client = clickhouse_connect.get_client(
                host=self.config.host,
                port=self.config.port,
                username=self.config.user,
                password=self.config.password or None,
                database=self.config.database,
            )
            logger.info(f"Connected to ClickHouse at {self.config.host}:{self.config.port}")
        return self._client
    
    def test_connection(self) -> bool:
        """Test database connectivity. Resets the connection on failure so the
        next call will create a fresh client rather than retrying a dead one."""
        try:
            result = self.client.command("SELECT 1")
            return result == 1
        except Exception as e:
            logger.error("ClickHouse connection test failed: %s", e)
            self._client = None  # force reconnect on next access
            return False

    def execute(self, query: str) -> Tuple[List[Dict[str, Any]], List[str]]:
        """
        Execute SQL query.

        Returns:
            Tuple of (rows as list of dicts, column names)

        Raises:
            Exception: Propagates ClickHouse errors after resetting the internal
                       client so the next call attempts a fresh reconnection.
        """
        logger.debug("Executing: %s", query[:200])
        try:
            result = self.client.query(query)
            columns = result.column_names
            rows = [dict(zip(columns, row)) for row in result.result_rows]
            logger.debug("Returned %d rows", len(rows))
            return rows, columns
        except Exception as e:
            logger.error("ClickHouse query failed: %s", e)
            self._client = None  # force reconnect on next access
            raise
    
    def execute_raw(self, query: str) -> str:
        """Execute query and return formatted string result."""
        rows, columns = self.execute(query)
        
        if not rows:
            return "No results found."
        
        lines = [" | ".join(columns), "-" * 50]
        for row in rows[:30]:
            lines.append(" | ".join(str(row.get(c, "")) for c in columns))
        
        if len(rows) > 30:
            lines.append(f"... ({len(rows) - 30} more rows)")
        
        return "\n".join(lines)
    
    def get_categories(self) -> List[str]:
        """Get distinct categories."""
        rows, _ = self.execute(
            f"SELECT DISTINCT category FROM {self.config.database}.{self.config.table} ORDER BY category"
        )
        return [r["category"] for r in rows]
    
    def get_applications(self) -> List[Dict[str, str]]:
        """Get distinct applications."""
        rows, _ = self.execute(
            f"SELECT DISTINCT _idApplication, applicationName FROM {self.config.database}.{self.config.table} ORDER BY applicationName"
        )
        return rows
    
    def get_time_range(self) -> Dict[str, Any]:
        """Get data time range."""
        rows, _ = self.execute(
            f"SELECT min(periodStart) as earliest, max(periodStart) as latest, count() as total FROM {self.config.database}.{self.config.table}"
        )
        return rows[0] if rows else {}
    
    def close(self):
        if self._client:
            self._client.close()
            self._client = None


# Singleton
_client: Optional[ClickHouseClient] = None

def get_clickhouse() -> ClickHouseClient:
    global _client
    if _client is None:
        _client = ClickHouseClient()
    return _client