# ============================================================
# src/accountable_record/stage_080_generated/base/diagnostics.py
# ============================================================
"""Stage 080 generated-artifact diagnostic definitions.

WHY:
    Diagnostic codes, severities, and messages belong together. Keeping each
    diagnostic as one definition prevents code constants and message builders
    from drifting independently.

OBS:
    This module defines the AR.GN.* diagnostics stage 080 may emit. It does
    not collect generated artifacts, compare locks, compute digests, mutate
    pipeline state, or decide when diagnostics are emitted.

REQ:
    Public diagnostic names in this module are DiagnosticSpec objects.
"""

from accountable_record.pipeline.diagnostics import (
    Concern,
    DiagnosticSpec,
    Severity,
    ar_code,
    from_spec,
    from_spec_at,
)

__all__ = [
    "DiagnosticSpec",
    "EXPORTS_REQUIRED",
    "GENERATED_DIGEST_MISMATCH",
    "GENERATED_DUPLICATE_ID",
    "LOCK_GENERATED_MISSING",
    "from_spec",
    "from_spec_at",
]


def _exports_required_message() -> str:
    """Return a message for a missing upstream exports artifact."""
    return "s080_generated requires s060_exports to complete first."


def _generated_duplicate_id_message(*, compact_id: str) -> str:
    """Return a message for a duplicate element id among generated artifacts."""
    return f"generated artifacts contain duplicate element id {compact_id!r}"


def _lock_generated_missing_message(*, compact_id: str) -> str:
    """Return a message for a locked element with no generated artifact."""
    return f"locked element {compact_id!r} has no corresponding generated artifact"


def _generated_digest_mismatch_message(*, compact_id: str) -> str:
    """Return a message for a generated artifact digest mismatch."""
    return f"generated artifact {compact_id!r} digest does not match the locked digest"


EXPORTS_REQUIRED = DiagnosticSpec(
    code=ar_code(Concern.GENERATED, "EXPORTS_REQUIRED"),
    severity=Severity.ERROR,
    message=_exports_required_message,
    description="Stage 080 requires the stage 060 exports artifact to be present.",
)

GENERATED_DUPLICATE_ID = DiagnosticSpec(
    code=ar_code(Concern.GENERATED, "GENERATED_DUPLICATE_ID"),
    severity=Severity.ERROR,
    message=_generated_duplicate_id_message,
    description="Two generated artifacts collide on one element compact_id.",
)

LOCK_GENERATED_MISSING = DiagnosticSpec(
    code=ar_code(Concern.GENERATED, "LOCK_GENERATED_MISSING"),
    severity=Severity.ERROR,
    message=_lock_generated_missing_message,
    description="A locked element has no corresponding generated artifact.",
)

GENERATED_DIGEST_MISMATCH = DiagnosticSpec(
    code=ar_code(Concern.GENERATED, "GENERATED_DIGEST_MISMATCH"),
    severity=Severity.ERROR,
    message=_generated_digest_mismatch_message,
    description="A generated artifact digest does not match the lock digest.",
)
