"""Detect dimension vs fact tables using Kimball heuristics."""

from __future__ import annotations

import logging
from collections import Counter
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)


@dataclass
class DimensionCandidate:
    """A table identified as a likely dimension."""
    table: str
    inbound_references: int
    referencing_tables: List[str] = field(default_factory=list)


class DimensionDetector:
    """Detect dimension, fact, and bridge tables from relationship metadata.

    Kimball heuristic: tables referenced by >= N others are likely dimensions.
    Tables that reference many dimensions are likely facts.
    """

    def detect(
        self, relationships: List[Dict], threshold: int = 3
    ) -> List[DimensionCandidate]:
        """Find tables with >= threshold inbound FK references.

        Args:
            relationships: List of relationship dicts with 'target_table' and 'source_table'.
            threshold: Minimum inbound references to qualify as dimension.

        Returns:
            List of DimensionCandidate objects sorted by inbound_references desc.
        """
        inbound: Dict[str, List[str]] = {}
        for rel in relationships:
            tgt = rel.get("target_table", "")
            src = rel.get("source_table", "")
            if tgt and src:
                inbound.setdefault(tgt, []).append(src)

        candidates = []
        for table, refs in inbound.items():
            unique_refs = list(set(refs))
            if len(unique_refs) >= threshold:
                candidates.append(DimensionCandidate(
                    table=table,
                    inbound_references=len(unique_refs),
                    referencing_tables=unique_refs,
                ))

        return sorted(candidates, key=lambda c: c.inbound_references, reverse=True)

    def classify_tables(
        self,
        relationships: List[Dict],
        threshold: int = 3,
        ai_advisor: Optional[Any] = None,
        column_metadata: Optional[Dict[str, List[str]]] = None,
    ) -> Dict[str, str]:
        """Classify all tables as dimension, fact, bridge, or unknown.

        Logic:
        - dimension: >= threshold inbound references
        - fact: references >= 2 dimensions and has few inbound refs
        - bridge: exactly 2 outbound refs to dimensions (many-to-many resolver)
        - unknown: everything else

        Args:
            relationships: List of relationship dicts.
            threshold: Dimension detection threshold.

        Returns:
            Dict mapping table name to classification string.
        """
        dims = {c.table for c in self.detect(relationships, threshold)}

        # Count outbound refs to dimension tables per source
        outbound_to_dim: Dict[str, int] = Counter()
        inbound_count: Dict[str, int] = Counter()
        all_tables: set = set()

        for rel in relationships:
            src = rel.get("source_table", "")
            tgt = rel.get("target_table", "")
            if src:
                all_tables.add(src)
            if tgt:
                all_tables.add(tgt)
                inbound_count[tgt] += 1
            if src and tgt in dims:
                outbound_to_dim[src] += 1

        result: Dict[str, str] = {}
        for table in all_tables:
            if table in dims:
                result[table] = "dimension"
            elif outbound_to_dim.get(table, 0) == 2 and inbound_count.get(table, 0) <= 1:
                result[table] = "bridge"
            elif outbound_to_dim.get(table, 0) >= 2:
                result[table] = "fact"
            else:
                result[table] = "unknown"

        # AI enrichment (additive only)
        if ai_advisor and ai_advisor.available:
            try:
                enrichment = ai_advisor.enhance_classification(
                    classification=result,
                    relationships=relationships,
                    column_metadata=column_metadata,
                )
                if enrichment:
                    result["_ai_advisor"] = enrichment
            except Exception:
                logger.debug("AI advisor enrichment failed for classify_tables", exc_info=True)

        return result
