from __future__ import annotations

import base64
from collections.abc import Mapping, Sequence
from dataclasses import fields, is_dataclass
from pathlib import Path
from typing import Any, Callable, TypeVar

from models import (
    SCHEMA_VERSION,
    AlertRecord,
    ArtifactRecord,
    BatchDiagnosticRecord,
    EvidenceRecord,
    EventRecord,
    HealthScoreRecord,
    LayerSummaryRecord,
    LifecycleEventRecord,
    MetricRecord,
    NoteRecord,
    ParameterDistributionRecord,
    ParameterSummaryRecord,
    PhaseRecord,
    ProjectRecord,
    RunContext,
    RunRecord,
    SystemTelemetryRecord,
)

_STATUS_FROM_API = {
    "active": "running",
    "running": "running",
    "completed": "completed",
    "failed": "failed",
    "interrupted": "interrupted",
}
_STATUS_TO_API = {
    "running": "active",
    "completed": "completed",
    "failed": "failed",
    "interrupted": "interrupted",
}

_RecordParser = TypeVar("_RecordParser")


def unwrap_success_envelope(payload: Any) -> Any:
    if isinstance(payload, Mapping) and "data" in payload and "error" not in payload:
        return payload["data"]
    return payload


def decode_status(value: Any) -> Any:
    if value is None:
        return None
    if not isinstance(value, str):
        return value
    return _STATUS_FROM_API.get(value, value)


def encode_status(value: Any) -> Any:
    if value is None:
        return None
    if not isinstance(value, str):
        return value
    return _STATUS_TO_API.get(value, value)


def to_api_payload(value: Any) -> Any:
    if is_dataclass(value):
        payload: dict[str, Any] = {}
        for field in fields(value):
            raw_value = getattr(value, field.name)
            if raw_value is None:
                continue
            payload[field.name] = to_api_payload(raw_value)
        if "status" in payload:
            payload["status"] = encode_status(payload["status"])
        return payload
    if isinstance(value, Mapping):
        return {
            str(key): to_api_payload(item)
            for key, item in value.items()
        }
    if isinstance(value, tuple):
        return [to_api_payload(item) for item in value]
    if isinstance(value, list):
        return [to_api_payload(item) for item in value]
    return value


def run_context_from_payload(payload: Any, *, storage_dir: str | Path | None = None) -> RunContext:
    raw_payload = _as_mapping(unwrap_success_envelope(payload), label="RunContext")
    resolved_storage_dir = (
        str(Path(storage_dir).resolve())
        if storage_dir is not None
        else _optional_text(raw_payload.get("storage_dir"))
    )
    store_root = _optional_text(raw_payload.get("store_root"))
    db_path = _optional_text(raw_payload.get("db_path"))
    return RunContext(
        storage_dir=resolved_storage_dir or "",
        store_root=store_root or _default_store_root(resolved_storage_dir),
        db_path=db_path or _default_db_path(resolved_storage_dir),
        project=project_from_payload(raw_payload.get("project")),
        run=run_from_payload(raw_payload.get("run")),
    )


def project_from_payload(payload: Any) -> ProjectRecord:
    raw_payload = _as_mapping(payload, label="ProjectRecord")
    return ProjectRecord(
        id=_required_text(raw_payload.get("id"), "project.id"),
        name=_required_text(raw_payload.get("name"), "project.name"),
        root_path=_required_text(raw_payload.get("root_path"), "project.root_path"),
        created_at=_required_text(raw_payload.get("created_at"), "project.created_at"),
        updated_at=_required_text(raw_payload.get("updated_at"), "project.updated_at"),
        schema_version=_schema_version(raw_payload),
    )


def note_from_payload(payload: Any) -> NoteRecord:
    raw_payload = _as_mapping(payload, label="NoteRecord")
    return NoteRecord(
        id=_required_text(raw_payload.get("id"), "note.id"),
        run_id=_required_text(raw_payload.get("run_id"), "note.run_id"),
        note=_required_text(raw_payload.get("note"), "note.note"),
        created_at=_required_text(raw_payload.get("created_at"), "note.created_at"),
        schema_version=_schema_version(raw_payload),
    )


def lifecycle_event_from_payload(payload: Any) -> LifecycleEventRecord:
    raw_payload = _as_mapping(payload, label="LifecycleEventRecord")
    return LifecycleEventRecord(
        id=_required_text(raw_payload.get("id"), "lifecycle_event.id"),
        run_id=_required_text(raw_payload.get("run_id"), "lifecycle_event.run_id"),
        event_type=_required_text(raw_payload.get("event_type"), "lifecycle_event.event_type"),
        timestamp=_required_text(raw_payload.get("timestamp"), "lifecycle_event.timestamp"),
        status=decode_status(raw_payload.get("status")) or "running",
        payload=_mapping_payload(raw_payload.get("payload")),
        schema_version=_schema_version(raw_payload),
    )


def run_from_payload(payload: Any) -> RunRecord:
    raw_payload = _as_mapping(payload, label="RunRecord")
    return RunRecord(
        id=_required_text(raw_payload.get("id"), "run.id"),
        project_id=_required_text(raw_payload.get("project_id"), "run.project_id"),
        project_name=_required_text(raw_payload.get("project_name"), "run.project_name"),
        status=decode_status(raw_payload.get("status")) or "running",
        created_at=_required_text(raw_payload.get("created_at"), "run.created_at"),
        started_at=_required_text(raw_payload.get("started_at"), "run.started_at"),
        updated_at=_required_text(raw_payload.get("updated_at"), "run.updated_at"),
        ended_at=_optional_text(raw_payload.get("ended_at")),
        parent_run_id=_optional_text(raw_payload.get("parent_run_id")),
        lineage_root_run_id=_required_text(
            raw_payload.get("lineage_root_run_id"),
            "run.lineage_root_run_id",
        ),
        resume_count=_optional_int(raw_payload.get("resume_count")) or 0,
        latest_resume_at=_optional_text(raw_payload.get("latest_resume_at")),
        config_path=_required_text(raw_payload.get("config_path"), "run.config_path"),
        environment_path=_required_text(raw_payload.get("environment_path"), "run.environment_path"),
        run_path=_required_text(raw_payload.get("run_path"), "run.run_path"),
        git_commit=_optional_text(raw_payload.get("git_commit")),
        strict_mode=bool(raw_payload.get("strict_mode", False)),
        tags=_string_tuple(raw_payload.get("tags")),
        notes=_record_tuple(raw_payload.get("notes"), note_from_payload),
        lifecycle_events=_record_tuple(
            raw_payload.get("lifecycle_events"),
            lifecycle_event_from_payload,
        ),
        schema_version=_schema_version(raw_payload),
    )


def event_from_payload(payload: Any) -> EventRecord:
    raw_payload = _as_mapping(payload, label="EventRecord")
    return EventRecord(
        id=_required_text(raw_payload.get("id"), "event.id"),
        run_id=_required_text(raw_payload.get("run_id"), "event.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "event.sequence_id"),
        event_type=_required_text(raw_payload.get("event_type"), "event.event_type"),
        severity=_required_text(raw_payload.get("severity"), "event.severity"),
        timestamp=_required_text(raw_payload.get("timestamp"), "event.timestamp"),
        step=_optional_int(raw_payload.get("step")),
        epoch=_optional_int(raw_payload.get("epoch")),
        status=decode_status(raw_payload.get("status")),
        payload=_mapping_payload(raw_payload.get("payload")),
        schema_version=_schema_version(raw_payload),
    )


def metric_from_payload(payload: Any) -> MetricRecord:
    raw_payload = _as_mapping(payload, label="MetricRecord")
    return MetricRecord(
        id=_required_text(raw_payload.get("id"), "metric.id"),
        run_id=_required_text(raw_payload.get("run_id"), "metric.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "metric.sequence_id"),
        namespace=_optional_text(raw_payload.get("namespace")) or "",
        metric_name=_required_text(raw_payload.get("metric_name"), "metric.metric_name"),
        metric_key=_required_text(raw_payload.get("metric_key"), "metric.metric_key"),
        value=_required_float(raw_payload.get("value"), "metric.value"),
        step=_optional_int(raw_payload.get("step")),
        epoch=_optional_int(raw_payload.get("epoch")),
        timestamp=_required_text(raw_payload.get("timestamp"), "metric.timestamp"),
        description=_optional_text(raw_payload.get("description")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def telemetry_from_payload(payload: Any) -> SystemTelemetryRecord:
    raw_payload = _as_mapping(payload, label="SystemTelemetryRecord")
    return SystemTelemetryRecord(
        id=_required_text(raw_payload.get("id"), "telemetry.id"),
        run_id=_required_text(raw_payload.get("run_id"), "telemetry.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "telemetry.sequence_id"),
        boundary=_required_text(raw_payload.get("boundary"), "telemetry.boundary"),
        timestamp=_required_text(raw_payload.get("timestamp"), "telemetry.timestamp"),
        cpu_backend=_required_text(raw_payload.get("cpu_backend"), "telemetry.cpu_backend"),
        gpu_backend=_required_text(raw_payload.get("gpu_backend"), "telemetry.gpu_backend"),
        overflow_count=_required_int(raw_payload.get("overflow_count"), "telemetry.overflow_count"),
        skipped_step_count=_required_int(
            raw_payload.get("skipped_step_count"),
            "telemetry.skipped_step_count",
        ),
        step=_optional_int(raw_payload.get("step")),
        epoch=_optional_int(raw_payload.get("epoch")),
        step_time_ms=_optional_float(raw_payload.get("step_time_ms")),
        data_time_ms=_optional_float(raw_payload.get("data_time_ms")),
        compute_time_ms=_optional_float(raw_payload.get("compute_time_ms")),
        cpu_usage_percent=_optional_float(raw_payload.get("cpu_usage_percent")),
        cpu_fallback_reason=_optional_text(raw_payload.get("cpu_fallback_reason")),
        ram_used_bytes=_optional_int(raw_payload.get("ram_used_bytes")),
        ram_total_bytes=_optional_int(raw_payload.get("ram_total_bytes")),
        ram_available_bytes=_optional_int(raw_payload.get("ram_available_bytes")),
        ram_usage_percent=_optional_float(raw_payload.get("ram_usage_percent")),
        process_rss_bytes=_optional_int(raw_payload.get("process_rss_bytes")),
        gpu_index=_optional_int(raw_payload.get("gpu_index")),
        gpu_name=_optional_text(raw_payload.get("gpu_name")),
        gpu_utilization_percent=_optional_float(raw_payload.get("gpu_utilization_percent")),
        gpu_memory_used_bytes=_optional_int(raw_payload.get("gpu_memory_used_bytes")),
        gpu_memory_total_bytes=_optional_int(raw_payload.get("gpu_memory_total_bytes")),
        gpu_memory_usage_percent=_optional_float(raw_payload.get("gpu_memory_usage_percent")),
        gpu_fallback_reason=_optional_text(raw_payload.get("gpu_fallback_reason")),
        overflow_occurred=bool(raw_payload.get("overflow_occurred", False)),
        step_skipped=bool(raw_payload.get("step_skipped", False)),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def layer_summary_from_payload(payload: Any) -> LayerSummaryRecord:
    raw_payload = _as_mapping(payload, label="LayerSummaryRecord")
    return LayerSummaryRecord(
        id=_required_text(raw_payload.get("id"), "layer_summary.id"),
        run_id=_required_text(raw_payload.get("run_id"), "layer_summary.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "layer_summary.sequence_id"),
        step=_required_int(raw_payload.get("step"), "layer_summary.step"),
        epoch=_optional_int(raw_payload.get("epoch")),
        module_name=_required_text(raw_payload.get("module_name"), "layer_summary.module_name"),
        module_type=_required_text(raw_payload.get("module_type"), "layer_summary.module_type"),
        summary_type=_required_text(raw_payload.get("summary_type"), "layer_summary.summary_type"),
        hook_direction=_required_text(
            raw_payload.get("hook_direction"),
            "layer_summary.hook_direction",
        ),
        call_index=_required_int(raw_payload.get("call_index"), "layer_summary.call_index"),
        element_count=_required_int(raw_payload.get("element_count"), "layer_summary.element_count"),
        timestamp=_required_text(raw_payload.get("timestamp"), "layer_summary.timestamp"),
        tensor_shape=_optional_int_tuple(raw_payload.get("tensor_shape")),
        mean=_optional_float(raw_payload.get("mean")),
        std=_optional_float(raw_payload.get("std")),
        norm=_optional_float(raw_payload.get("norm")),
        variance=_optional_float(raw_payload.get("variance")),
        dead_unit_ratio=_optional_float(raw_payload.get("dead_unit_ratio")),
        saturation_ratio=_optional_float(raw_payload.get("saturation_ratio")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def parameter_summary_from_payload(payload: Any) -> ParameterSummaryRecord:
    raw_payload = _as_mapping(payload, label="ParameterSummaryRecord")
    return ParameterSummaryRecord(
        id=_required_text(raw_payload.get("id"), "parameter_summary.id"),
        run_id=_required_text(raw_payload.get("run_id"), "parameter_summary.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "parameter_summary.sequence_id"),
        step=_required_int(raw_payload.get("step"), "parameter_summary.step"),
        epoch=_optional_int(raw_payload.get("epoch")),
        timestamp=_required_text(raw_payload.get("timestamp"), "parameter_summary.timestamp"),
        module_name=_required_text(raw_payload.get("module_name"), "parameter_summary.module_name"),
        module_type=_optional_text(raw_payload.get("module_type")),
        parameter_name=_required_text(raw_payload.get("parameter_name"), "parameter_summary.parameter_name"),
        parameter_key=_required_text(raw_payload.get("parameter_key"), "parameter_summary.parameter_key"),
        parameter_role=_required_text(raw_payload.get("parameter_role"), "parameter_summary.parameter_role"),
        tensor_shape=_optional_int_tuple(raw_payload.get("tensor_shape")),
        dtype=_optional_text(raw_payload.get("dtype")),
        requires_grad=_optional_bool(raw_payload.get("requires_grad")),
        element_count=_required_int(raw_payload.get("element_count"), "parameter_summary.element_count"),
        mean=_optional_float(raw_payload.get("mean")),
        std=_optional_float(raw_payload.get("std")),
        variance=_optional_float(raw_payload.get("variance")),
        norm=_optional_float(raw_payload.get("norm")),
        min=_optional_float(raw_payload.get("min")),
        max=_optional_float(raw_payload.get("max")),
        abs_mean=_optional_float(raw_payload.get("abs_mean")),
        abs_max=_optional_float(raw_payload.get("abs_max")),
        zero_ratio=_optional_float(raw_payload.get("zero_ratio")),
        near_zero_ratio=_optional_float(raw_payload.get("near_zero_ratio")),
        finite_ratio=_optional_float(raw_payload.get("finite_ratio")),
        nan_count=_optional_int(raw_payload.get("nan_count")),
        inf_count=_optional_int(raw_payload.get("inf_count")),
        grad_mean=_optional_float(raw_payload.get("grad_mean")),
        grad_std=_optional_float(raw_payload.get("grad_std")),
        grad_norm=_optional_float(raw_payload.get("grad_norm")),
        grad_abs_max=_optional_float(raw_payload.get("grad_abs_max")),
        update_norm=_optional_float(raw_payload.get("update_norm")),
        update_mean=_optional_float(raw_payload.get("update_mean")),
        update_std=_optional_float(raw_payload.get("update_std")),
        update_to_parameter_norm_ratio=_optional_float(
            raw_payload.get("update_to_parameter_norm_ratio")
        ),
        optimizer_name=_optional_text(raw_payload.get("optimizer_name")),
        optimizer_group_index=_optional_int(raw_payload.get("optimizer_group_index")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def parameter_distribution_from_payload(payload: Any) -> ParameterDistributionRecord:
    raw_payload = _as_mapping(payload, label="ParameterDistributionRecord")
    return ParameterDistributionRecord(
        id=_required_text(raw_payload.get("id"), "parameter_distribution.id"),
        run_id=_required_text(raw_payload.get("run_id"), "parameter_distribution.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "parameter_distribution.sequence_id"),
        step=_required_int(raw_payload.get("step"), "parameter_distribution.step"),
        epoch=_optional_int(raw_payload.get("epoch")),
        timestamp=_required_text(raw_payload.get("timestamp"), "parameter_distribution.timestamp"),
        module_name=_required_text(raw_payload.get("module_name"), "parameter_distribution.module_name"),
        module_type=_optional_text(raw_payload.get("module_type")),
        parameter_name=_required_text(
            raw_payload.get("parameter_name"),
            "parameter_distribution.parameter_name",
        ),
        parameter_key=_required_text(
            raw_payload.get("parameter_key"),
            "parameter_distribution.parameter_key",
        ),
        parameter_role=_required_text(
            raw_payload.get("parameter_role"),
            "parameter_distribution.parameter_role",
        ),
        distribution_type=_required_text(
            raw_payload.get("distribution_type"),
            "parameter_distribution.distribution_type",
        ),
        bin_edges=_float_tuple(raw_payload.get("bin_edges")),
        counts=_int_tuple(raw_payload.get("counts")),
        density=bool(raw_payload.get("density", False)),
        sample_count=_required_int(raw_payload.get("sample_count"), "parameter_distribution.sample_count"),
        total_count=_optional_int(raw_payload.get("total_count")),
        min=_optional_float(raw_payload.get("min")),
        max=_optional_float(raw_payload.get("max")),
        nan_count=_optional_int(raw_payload.get("nan_count")),
        inf_count=_optional_int(raw_payload.get("inf_count")),
        clipped_low_count=_optional_int(raw_payload.get("clipped_low_count")),
        clipped_high_count=_optional_int(raw_payload.get("clipped_high_count")),
        summary_id=_optional_text(raw_payload.get("summary_id")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def batch_diagnostic_from_payload(payload: Any) -> BatchDiagnosticRecord:
    raw_payload = _as_mapping(payload, label="BatchDiagnosticRecord")
    return BatchDiagnosticRecord(
        id=_required_text(raw_payload.get("id"), "batch_diagnostic.id"),
        run_id=_required_text(raw_payload.get("run_id"), "batch_diagnostic.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "batch_diagnostic.sequence_id"),
        loss=_required_float(raw_payload.get("loss"), "batch_diagnostic.loss"),
        timestamp=_required_text(raw_payload.get("timestamp"), "batch_diagnostic.timestamp"),
        step=_optional_int(raw_payload.get("step")),
        epoch=_optional_int(raw_payload.get("epoch")),
        batch_size=_optional_int(raw_payload.get("batch_size")),
        sample_ids=_string_tuple(raw_payload.get("sample_ids")),
        class_counts=_int_mapping(raw_payload.get("class_counts")),
        sequence_lengths=_int_tuple(raw_payload.get("sequence_lengths")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def artifact_from_payload(payload: Any) -> ArtifactRecord:
    raw_payload = _as_mapping(unwrap_success_envelope(payload), label="ArtifactRecord")
    return ArtifactRecord(
        id=_required_text(raw_payload.get("id"), "artifact.id"),
        run_id=_required_text(raw_payload.get("run_id"), "artifact.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "artifact.sequence_id"),
        artifact_type=_required_text(raw_payload.get("artifact_type"), "artifact.artifact_type"),
        namespace=_optional_text(raw_payload.get("namespace")) or "",
        artifact_name=_required_text(raw_payload.get("artifact_name"), "artifact.artifact_name"),
        artifact_key=_required_text(raw_payload.get("artifact_key"), "artifact.artifact_key"),
        payload_format=_required_text(raw_payload.get("payload_format"), "artifact.payload_format"),
        content_type=_required_text(raw_payload.get("content_type"), "artifact.content_type"),
        payload_path=_required_text(raw_payload.get("payload_path"), "artifact.payload_path"),
        payload_relative_path=_required_text(
            raw_payload.get("payload_relative_path"),
            "artifact.payload_relative_path",
        ),
        metadata_path=_required_text(raw_payload.get("metadata_path"), "artifact.metadata_path"),
        metadata_relative_path=_required_text(
            raw_payload.get("metadata_relative_path"),
            "artifact.metadata_relative_path",
        ),
        step=_optional_int(raw_payload.get("step")),
        epoch=_optional_int(raw_payload.get("epoch")),
        timestamp=_required_text(raw_payload.get("timestamp"), "artifact.timestamp"),
        size_bytes=_required_int(raw_payload.get("size_bytes"), "artifact.size_bytes"),
        sha256=_required_text(raw_payload.get("sha256"), "artifact.sha256"),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def evidence_from_payload(payload: Any) -> EvidenceRecord:
    raw_payload = _as_mapping(payload, label="EvidenceRecord")
    return EvidenceRecord(
        kind=_required_text(raw_payload.get("kind"), "evidence.kind"),
        source=_required_text(raw_payload.get("source"), "evidence.source"),
        summary=_required_text(raw_payload.get("summary"), "evidence.summary"),
        observed_value=raw_payload.get("observed_value"),
        threshold_value=raw_payload.get("threshold_value"),
        step=_optional_int(raw_payload.get("step")),
        step_start=_optional_int(raw_payload.get("step_start")),
        step_end=_optional_int(raw_payload.get("step_end")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def alert_from_payload(payload: Any) -> AlertRecord:
    raw_payload = _as_mapping(payload, label="AlertRecord")
    return AlertRecord(
        id=_required_text(raw_payload.get("id"), "alert.id"),
        run_id=_required_text(raw_payload.get("run_id"), "alert.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "alert.sequence_id"),
        rule_id=_required_text(raw_payload.get("rule_id"), "alert.rule_id"),
        category=_required_text(raw_payload.get("category"), "alert.category"),
        severity=_required_text(raw_payload.get("severity"), "alert.severity"),
        title=_required_text(raw_payload.get("title"), "alert.title"),
        summary=_required_text(raw_payload.get("summary"), "alert.summary"),
        fact=_required_text(raw_payload.get("fact"), "alert.fact"),
        inference=_required_text(raw_payload.get("inference"), "alert.inference"),
        timestamp=_required_text(raw_payload.get("timestamp"), "alert.timestamp"),
        step=_optional_int(raw_payload.get("step")),
        step_start=_optional_int(raw_payload.get("step_start")),
        step_end=_optional_int(raw_payload.get("step_end")),
        evidence=_record_tuple(raw_payload.get("evidence"), evidence_from_payload),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def health_score_from_payload(payload: Any) -> HealthScoreRecord:
    raw_payload = _as_mapping(payload, label="HealthScoreRecord")
    return HealthScoreRecord(
        id=_required_text(raw_payload.get("id"), "health_score.id"),
        run_id=_required_text(raw_payload.get("run_id"), "health_score.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "health_score.sequence_id"),
        score_key=_required_text(raw_payload.get("score_key"), "health_score.score_key"),
        category=_required_text(raw_payload.get("category"), "health_score.category"),
        score=_required_float(raw_payload.get("score"), "health_score.score"),
        status=_required_text(raw_payload.get("status"), "health_score.status"),
        summary=_required_text(raw_payload.get("summary"), "health_score.summary"),
        timestamp=_required_text(raw_payload.get("timestamp"), "health_score.timestamp"),
        step_start=_optional_int(raw_payload.get("step_start")),
        step_end=_optional_int(raw_payload.get("step_end")),
        evidence=_record_tuple(raw_payload.get("evidence"), evidence_from_payload),
        contributing_alert_ids=_string_tuple(raw_payload.get("contributing_alert_ids")),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def phase_from_payload(payload: Any) -> PhaseRecord:
    raw_payload = _as_mapping(payload, label="PhaseRecord")
    return PhaseRecord(
        id=_required_text(raw_payload.get("id"), "phase.id"),
        run_id=_required_text(raw_payload.get("run_id"), "phase.run_id"),
        sequence_id=_required_int(raw_payload.get("sequence_id"), "phase.sequence_id"),
        phase_name=_required_text(raw_payload.get("phase_name"), "phase.phase_name"),
        display_name=_required_text(raw_payload.get("display_name"), "phase.display_name"),
        summary=_required_text(raw_payload.get("summary"), "phase.summary"),
        step_start=_required_int(raw_payload.get("step_start"), "phase.step_start"),
        step_end=_required_int(raw_payload.get("step_end"), "phase.step_end"),
        timestamp=_required_text(raw_payload.get("timestamp"), "phase.timestamp"),
        evidence=_record_tuple(raw_payload.get("evidence"), evidence_from_payload),
        metadata=_mapping_or_none(raw_payload.get("metadata")),
        schema_version=_schema_version(raw_payload),
    )


def record_list_from_payload(payload: Any, parser: Callable[[Any], _RecordParser]) -> tuple[_RecordParser, ...]:
    raw_payload = unwrap_success_envelope(payload)
    if raw_payload is None:
        return ()
    if not isinstance(raw_payload, Sequence) or isinstance(raw_payload, (str, bytes, bytearray)):
        raise TypeError("Expected a list response payload from the persistence service.")
    return tuple(parser(item) for item in raw_payload)


def analysis_outputs_from_payload(payload: Any) -> tuple[tuple[AlertRecord, ...], tuple[HealthScoreRecord, ...]]:
    raw_payload = _as_mapping(unwrap_success_envelope(payload), label="analysis_outputs")
    return (
        _record_tuple(raw_payload.get("alerts"), alert_from_payload),
        _record_tuple(raw_payload.get("health_scores"), health_score_from_payload),
    )


def artifact_payload_from_payload(payload: Any) -> Any:
    raw_payload = _as_mapping(unwrap_success_envelope(payload), label="ArtifactPayloadResponse")
    payload_format = _required_text(raw_payload.get("payload_format"), "artifact_payload.payload_format")
    if payload_format == "bytes":
        encoded = _optional_text(raw_payload.get("payload_base64")) or ""
        return base64.b64decode(encoded.encode("utf-8"))
    return raw_payload.get("payload")


def sequence_from_payload(payload: Any) -> int:
    raw_payload = _as_mapping(unwrap_success_envelope(payload), label="SequenceResponse")
    return _required_int(raw_payload.get("sequence"), "sequence")


def _as_mapping(value: Any, *, label: str) -> Mapping[str, Any]:
    if not isinstance(value, Mapping):
        raise TypeError(f"{label} payload must be a mapping.")
    return value


def _schema_version(payload: Mapping[str, Any]) -> int:
    value = payload.get("schema_version")
    if value is None:
        return SCHEMA_VERSION
    return int(value)


def _required_text(value: Any, label: str) -> str:
    if not isinstance(value, str):
        raise TypeError(f"{label} must be a string.")
    candidate = value.strip()
    if not candidate:
        raise ValueError(f"{label} must not be empty.")
    return candidate


def _optional_text(value: Any) -> str | None:
    if value is None:
        return None
    if not isinstance(value, str):
        return str(value)
    candidate = value.strip()
    return candidate or None


def _required_int(value: Any, label: str) -> int:
    if isinstance(value, bool) or not isinstance(value, int):
        raise TypeError(f"{label} must be an integer.")
    return int(value)


def _optional_int(value: Any) -> int | None:
    if value is None:
        return None
    if isinstance(value, bool) or not isinstance(value, int):
        raise TypeError("Expected an integer value from the persistence service.")
    return int(value)


def _optional_bool(value: Any) -> bool | None:
    if value is None:
        return None
    if not isinstance(value, bool):
        raise TypeError("Expected a boolean value from the persistence service.")
    return bool(value)


def _required_float(value: Any, label: str) -> float:
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise TypeError(f"{label} must be numeric.")
    return float(value)


def _optional_float(value: Any) -> float | None:
    if value is None:
        return None
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise TypeError("Expected a numeric value from the persistence service.")
    return float(value)


def _mapping_payload(value: Any) -> dict[str, Any]:
    if value is None:
        return {}
    if not isinstance(value, Mapping):
        raise TypeError("Expected a JSON object from the persistence service.")
    return dict(value)


def _mapping_or_none(value: Any) -> dict[str, Any] | None:
    if value is None:
        return None
    if not isinstance(value, Mapping):
        raise TypeError("Expected a JSON object from the persistence service.")
    return dict(value)


def _string_tuple(value: Any) -> tuple[str, ...]:
    items = _sequence_items(value)
    return tuple(str(item) for item in items if item is not None)


def _int_tuple(value: Any) -> tuple[int, ...]:
    if value is None:
        return ()
    items = _sequence_items(value)
    return tuple(int(item) for item in items)


def _float_tuple(value: Any) -> tuple[float, ...]:
    if value is None:
        return ()
    items = _sequence_items(value)
    return tuple(float(item) for item in items)


def _optional_int_tuple(value: Any) -> tuple[int, ...] | None:
    if value is None:
        return None
    return _int_tuple(value)


def _int_mapping(value: Any) -> dict[str, int]:
    if value is None:
        return {}
    if not isinstance(value, Mapping):
        raise TypeError("Expected a JSON object from the persistence service.")
    return {
        str(key): int(item)
        for key, item in value.items()
    }


def _record_tuple(
    value: Any,
    parser: Callable[[Any], _RecordParser],
) -> tuple[_RecordParser, ...]:
    if value is None:
        return ()
    return tuple(parser(item) for item in _sequence_items(value))


def _sequence_items(value: Any) -> tuple[Any, ...]:
    if value is None:
        return ()
    if not isinstance(value, Sequence) or isinstance(value, (str, bytes, bytearray)):
        raise TypeError("Expected a list response payload from the persistence service.")
    return tuple(value)


def _default_store_root(storage_dir: str | None) -> str:
    if not storage_dir:
        return ""
    return str(Path(storage_dir) / ".quark")


def _default_db_path(storage_dir: str | None) -> str:
    if not storage_dir:
        return ""
    return str(Path(storage_dir) / ".quark" / "projects.db")
