"""Async chain store backed by SQLAlchemy for server-side hash chain operations."""

from __future__ import annotations

from typing import Optional

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from kredo_drift.chain import ChainEntryModel
from kredo_drift.server.db.models import ChainEntry as ChainEntryDB


class AsyncChainStore:
    """SQLAlchemy-backed chain store for use in async server routes."""

    def __init__(self, db: AsyncSession):
        self._db = db

    def _to_model(self, row: ChainEntryDB) -> ChainEntryModel:
        return ChainEntryModel(
            agent_pubkey=row.agent_pubkey,
            sequence=row.sequence,
            event_type=row.event_type,
            content_hash=row.content_hash,
            prev_hash=row.prev_hash,
            chain_hash=row.chain_hash,
            created_at=row.created_at,
        )

    async def get_latest_entry(self, agent_pubkey: str) -> Optional[ChainEntryModel]:
        result = await self._db.execute(
            select(ChainEntryDB)
            .where(ChainEntryDB.agent_pubkey == agent_pubkey)
            .order_by(ChainEntryDB.sequence.desc())
            .limit(1)
        )
        row = result.scalar_one_or_none()
        return self._to_model(row) if row else None

    async def get_chain(self, agent_pubkey: str) -> list[ChainEntryModel]:
        result = await self._db.execute(
            select(ChainEntryDB)
            .where(ChainEntryDB.agent_pubkey == agent_pubkey)
            .order_by(ChainEntryDB.sequence)
        )
        return [self._to_model(row) for row in result.scalars().all()]

    async def save_entry(self, entry: ChainEntryModel) -> None:
        db_entry = ChainEntryDB(
            chain_hash=entry.chain_hash,
            agent_pubkey=entry.agent_pubkey,
            sequence=entry.sequence,
            event_type=entry.event_type,
            content_hash=entry.content_hash,
            prev_hash=entry.prev_hash,
            created_at=entry.created_at,
        )
        self._db.add(db_entry)


async def append_to_chain_async(
    agent_pubkey: str,
    event_type: str,
    content_hash: str,
    db: AsyncSession,
) -> ChainEntryModel:
    """Async version of append_to_chain that uses SQLAlchemy session."""
    from kredo_drift.chain import compute_chain_hash

    store = AsyncChainStore(db)
    latest = await store.get_latest_entry(agent_pubkey)

    if latest is None:
        sequence = 0
        prev_hash = None
    else:
        sequence = latest.sequence + 1
        prev_hash = latest.chain_hash

    chain_hash = compute_chain_hash(content_hash, prev_hash)

    entry = ChainEntryModel(
        agent_pubkey=agent_pubkey,
        sequence=sequence,
        event_type=event_type,
        content_hash=content_hash,
        prev_hash=prev_hash,
        chain_hash=chain_hash,
    )

    await store.save_entry(entry)
    return entry
