from __future__ import annotations

from dataclasses import asdict
from pathlib import Path
from typing import Callable, Iterable, TypeVar

from .analysis import SequenceAnalysis, analyze_sequence
from .runtime import ExecutionRecord
from .types import RunReport


StateT = TypeVar("StateT")
CandidateT = TypeVar("CandidateT")
MetadataT = TypeVar("MetadataT")


def summarize_execution(
    record: ExecutionRecord[StateT, CandidateT, MetadataT],
    *,
    parameters: dict[str, object] | None = None,
    sequence: Iterable[int] | None = None,
    alphabet_size: int | None = None,
) -> RunReport:
    sequence_analysis: dict[str, float | int] = {}
    if sequence is not None:
        if alphabet_size is None:
            raise ValueError("alphabet_size is required when sequence is provided")
        analysis = analyze_sequence(tuple(sequence), alphabet_size=alphabet_size)
        sequence_analysis = asdict(analysis)

    return RunReport(
        parameters=dict(parameters or {}),
        accepted_count=record.accepted_count,
        attempt_count=record.attempt_count,
        total_seconds=record.total_seconds,
        sequence_analysis=sequence_analysis,
        average_attempts_per_accept=(
            record.attempt_count / record.accepted_count if record.accepted_count else 0.0
        ),
    )


def summarize_sequence_run(
    record: ExecutionRecord[StateT, CandidateT, MetadataT],
    *,
    sequence_getter: Callable[[ExecutionRecord[StateT, CandidateT, MetadataT]], Iterable[int]],
    alphabet_size: int,
    parameters: dict[str, object] | None = None,
) -> RunReport:
    return summarize_execution(
        record,
        parameters=parameters,
        sequence=tuple(sequence_getter(record)),
        alphabet_size=alphabet_size,
    )


def save_run_report_json(report: RunReport, path: str | Path) -> None:
    from .artifacts import save_artifact_json

    save_artifact_json("run_report", report, path)
