"""Top-level reconcile() function for local identity resolution."""
from __future__ import annotations

import json
from dataclasses import dataclass, field
from typing import Any

from .source import Source
from .spec import Spec
from .validate import validate


@dataclass
class ReconcileResult:
    """Result of a local reconciliation run."""

    clusters: list[list[str]]
    golden_records: list[dict[str, str]]
    decisions: list[dict[str, Any]]
    telemetry: dict[str, Any]

    @property
    def cluster_count(self) -> int:
        return len(self.clusters)

    @property
    def merge_rate(self) -> float:
        """Fraction of input entities that were merged (1 - clusters/entities)."""
        total = sum(len(c) for c in self.clusters)
        if total == 0:
            return 0.0
        return 1.0 - (len(self.clusters) / total)

    def to_pandas(self) -> Any:
        """Convert golden records to a pandas DataFrame (requires pandas)."""
        try:
            import pandas as pd
        except ImportError:
            raise ImportError(
                "ReconcileResult.to_pandas() requires pandas: pip install pandas"
            ) from None
        return pd.DataFrame(self.golden_records)


def reconcile(
    sources: list[Source],
    spec: Spec,
) -> ReconcileResult:
    """Run local identity resolution across sources using the given spec.

    1. Validate the spec
    2. Collect entities from all sources
    3. Run the Rust reconciliation engine via PyO3
    4. Return structured results

    Args:
        sources: List of data sources to reconcile.
        spec: The identity spec defining rules and thresholds.
    """
    from kanoniv._native import reconcile_local

    # 1. Validate
    result = validate(spec)
    result.raise_on_error()

    # 2. Extract entity_type from spec
    entity = spec.entity
    if isinstance(entity, dict):
        entity_type = entity.get("name", "entity")
    else:
        entity_type = entity or "entity"

    # 3. Build attribute mappings from spec (canonical_name → source_column per source)
    #    spec.sources[i].attributes = {"email": "email_address", "phone": "phone_number"}
    #    means: entity.data["email"] = row["email_address"]
    attr_maps: dict[str, dict[str, str]] = {}
    for spec_src in spec.sources:
        src_name = spec_src.get("name", "")
        attrs = spec_src.get("attributes", {})
        if attrs and src_name:
            # attrs is {canonical: source_column}, we need {source_column: canonical}
            attr_maps[src_name] = {v: k for k, v in attrs.items()}

    # 4. Collect entities from all sources, applying attribute mappings
    all_entities: list[dict[str, Any]] = []
    for source in sources:
        entities = source.to_entities(entity_type)
        reverse_map = attr_maps.get(source.name, {})
        if reverse_map:
            for entity in entities:
                raw_data = entity["data"]
                mapped: dict[str, str] = {}
                for col, val in raw_data.items():
                    canonical = reverse_map.get(col, col)
                    mapped[canonical] = val
                entity["data"] = mapped
        all_entities.extend(entities)

    # 5. Serialize and call native engine
    entities_json = json.dumps(all_entities)
    raw = reconcile_local(spec.raw, entities_json)

    # 6. Unpack into ReconcileResult
    return ReconcileResult(
        clusters=raw.get("clusters", []),
        golden_records=raw.get("golden_records", []),
        decisions=raw.get("decisions", []),
        telemetry=raw.get("telemetry", {}),
    )
