"""Data export — write results to CSV, JSON, and DOT files.

Provides a unified interface for exporting DAG structures, credit risk
results (ECL, fairness), and discovery metrics to standard formats.

Stdlib-only (no pandas, no numpy).
"""

from __future__ import annotations

import csv
import io
import json
from pathlib import Path
from typing import Any

from orxaq.kernel.world_dag import WorldDAG


class DAGCSVExporter:
    """Export WorldDAG edges and nodes as CSV."""

    @staticmethod
    def export_edges(dag: WorldDAG) -> str:
        """Export edges as CSV: source, target, mechanism, confidence, soliton_score."""
        buf = io.StringIO()
        writer = csv.writer(buf)
        writer.writerow(["source", "target", "mechanism", "confidence", "soliton_score"])
        for edge in sorted(dag.edges.values(), key=lambda e: (e.source, e.target)):
            writer.writerow(
                [
                    edge.source,
                    edge.target,
                    edge.mechanism,
                    f"{edge.confidence:.6f}",
                    f"{edge.soliton_score:.6f}",
                ]
            )
        return buf.getvalue()

    @staticmethod
    def export_nodes(dag: WorldDAG) -> str:
        """Export entities as CSV with columns: entity_id, name, causal_role, domain."""
        buf = io.StringIO()
        writer = csv.writer(buf)
        writer.writerow(["entity_id", "name", "causal_role", "variable_type", "domain"])
        for entity in sorted(dag.entities.values(), key=lambda e: e.entity_id):
            writer.writerow(
                [
                    entity.entity_id,
                    entity.name,
                    entity.causal_role.value,
                    entity.variable_type.value,
                    entity.domain,
                ]
            )
        return buf.getvalue()


class ResultExporter:
    """Export structured results to JSON or CSV.

    Works with any list-of-dicts data: ECL results, fairness analysis,
    discovery metrics, validation reports.
    """

    @staticmethod
    def to_json(records: list[dict], indent: int = 2) -> str:
        """Export records as JSON array."""
        return json.dumps(records, indent=indent, default=str)

    @staticmethod
    def to_csv(records: list[dict]) -> str:
        """Export records as CSV. Uses first record's keys as headers."""
        if not records:
            return ""
        buf = io.StringIO()
        fieldnames = list(records[0].keys())
        writer = csv.DictWriter(buf, fieldnames=fieldnames)
        writer.writeheader()
        for record in records:
            writer.writerow({k: record.get(k, "") for k in fieldnames})
        return buf.getvalue()

    @staticmethod
    def write(content: str, path: str | Path) -> Path:
        """Write export content to a file."""
        p = Path(path)
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(content)
        return p


def export_ecl_results(
    ecl_result_or_records: Any,
) -> list[dict]:
    """Format ECL result as list of dicts for export.

    Accepts either a CECLResult object or a pre-built list of dicts.
    """
    if isinstance(ecl_result_or_records, list):
        return ecl_result_or_records

    # Duck-type CECLResult: has total_ecl, ecl_by_segment, etc.
    result = ecl_result_or_records
    if hasattr(result, "ecl_by_segment"):
        return [
            {
                "segment": seg_name,
                "ecl": f"{seg_ecl:.4f}",
            }
            for seg_name, seg_ecl in result.ecl_by_segment.items()
        ] + [
            {
                "segment": "TOTAL",
                "ecl": f"{result.total_ecl:.4f}",
            }
        ]

    return []


def export_dag_summary(dag: WorldDAG) -> list[dict]:
    """Export DAG as a list of edge records with node metadata."""
    records = []
    for edge in sorted(dag.edges.values(), key=lambda e: (e.source, e.target)):
        src = dag.get_entity(edge.source)
        tgt = dag.get_entity(edge.target)
        records.append(
            {
                "source": edge.source,
                "source_name": src.name if src else "",
                "target": edge.target,
                "target_name": tgt.name if tgt else "",
                "mechanism": edge.mechanism,
                "confidence": edge.confidence,
                "soliton_score": edge.soliton_score,
                "edge_type": edge.edge_type,
            }
        )
    return records
