from __future__ import annotations

import uuid
from typing import Any

from sqlalchemy import select

from supply_infra.db.models.pipeline_outbox import PipelineOutbox
from supply_infra.db.repositories.base import BaseRepository


class PipelineOutboxRepository(BaseRepository[PipelineOutbox]):
    model = PipelineOutbox

    def get_by_idempotency_key(self, key: str) -> PipelineOutbox | None:
        stmt = select(PipelineOutbox).where(PipelineOutbox.idempotency_key == key)
        return self.session.scalar(stmt)

    def record_effect(
        self,
        *,
        run_id: str,
        step_run_id: str,
        effect_type: str,
        idempotency_key: str,
        payload_hash: str,
        payload: dict[str, Any] | None,
        payload_uri: str | None = None,
    ) -> PipelineOutbox:
        existing = self.get_by_idempotency_key(idempotency_key)
        if existing is not None:
            return existing
        return self.add(
            PipelineOutbox(
                outbox_id=str(uuid.uuid4()),
                run_id=run_id,
                step_run_id=step_run_id,
                effect_type=effect_type,
                idempotency_key=idempotency_key,
                payload_hash=payload_hash,
                payload_json=payload,
                payload_uri=payload_uri,
                status="dispatched",
                dry_run=False,
            )
        )

    def list_for_run(self, run_id: str) -> list[PipelineOutbox]:
        stmt = (
            select(PipelineOutbox)
            .where(PipelineOutbox.run_id == run_id)
            .order_by(PipelineOutbox.created_at)
        )
        return list(self.session.scalars(stmt).all())
