"""
cortex/hippo/compaction/utils.py — Async utility functions used by engine passes.
"""

from __future__ import annotations

import logging
from typing import Optional

from cortex.hippo.models import ContextItemRecord, SummaryRecord
from cortex.hippo.store.conversation_store import ConversationStore
from cortex.hippo.store.summary_store import SummaryStore
from cortex.hippo.summarize import SummarizeOptions, SummarizeResult

from .helpers import _escalation_result, estimate_tokens
from .types import FALLBACK_MAX_CHARS, SummarizeFn

logger = logging.getLogger(__name__)


async def _summarize_with_escalation(
    source_text: str,
    summarize: SummarizeFn,
    options: Optional[SummarizeOptions] = None,
) -> SummarizeResult:
    """Three-level escalation: normal → aggressive → deterministic fallback."""
    input_tokens = estimate_tokens(source_text)

    # Level 1: Normal
    result = await summarize(source_text, False, options)
    if estimate_tokens(result.content) < input_tokens:
        return _escalation_result(result, "normal")

    # Level 2: Aggressive
    result = await summarize(source_text, True, options)
    if estimate_tokens(result.content) < input_tokens:
        return _escalation_result(result, "aggressive")

    # Level 3: Deterministic fallback
    fallback = source_text[:FALLBACK_MAX_CHARS].rstrip()
    fallback += f"\n[Truncated from {input_tokens} tokens]"
    fallback += "\nExpand for details about: full conversation content"

    from cortex.hippo.quality import score_quality
    quality = score_quality(source_text, fallback, options.is_condensed if options else False)

    return SummarizeResult(
        content=fallback,
        quality_score=quality.total,
        quality_breakdown={
            "compression": quality.compression,
            "coherence": quality.coherence,
            "coverage": quality.coverage,
        },
        source="fallback",
        mode_used="aggressive",
    )


async def _get_item_tokens(
    item: ContextItemRecord,
    conversation_store: ConversationStore,
    summary_store: SummaryStore,
) -> int:
    """Get token count for a context item."""
    if item.item_type == "message" and item.message_id:
        msg = await conversation_store.get_message_by_id(item.message_id)
        return msg.token_count if msg else 0
    elif item.item_type == "summary" and item.summary_id:
        summary = await _get_summary_by_context_item(item, summary_store)
        return summary.token_count if summary else 0
    return 0


async def _get_summary_by_context_item(
    item: ContextItemRecord,
    summary_store: SummaryStore,
) -> Optional[SummaryRecord]:
    """Get summary record from a context item. Tries multiple owner_ids."""
    if not item.summary_id:
        return None
    # We need owner_id — try to get it from the summary directly
    # SummaryStore.get_summary requires owner_id, but we may not have it
    # Workaround: query directly
    conn = summary_store._conn
    async with conn.execute(
        """
        SELECT summary_id, conversation_id, owner_id, kind, depth,
               content, token_count, file_ids, earliest_at, latest_at,
               descendant_count, descendant_token_count, source_message_token_count,
               quality_score, embedding, signal_metadata, created_at
        FROM hippo_summaries WHERE summary_id = ?
        """,
        (item.summary_id,),
    ) as cur:
        row = await cur.fetchone()
        if not row:
            return None
        return SummaryRecord(
            summary_id=row[0], conversation_id=row[1], owner_id=row[2],
            kind=row[3], depth=row[4], content=row[5], token_count=row[6],
            file_ids=row[7], earliest_at=row[8], latest_at=row[9],
            descendant_count=row[10], descendant_token_count=row[11],
            source_message_token_count=row[12], quality_score=row[13],
            embedding=row[14], signal_metadata=row[15], created_at=row[16],
        )


async def _resolve_owner_id(
    conversation_id: int,
    conversation_store: ConversationStore,
) -> str:
    """Resolve owner_id for a conversation. Falls back to 'default'."""
    try:
        conn = conversation_store._conn
        async with conn.execute(
            "SELECT owner_id FROM hippo_conversations WHERE conversation_id = ?",
            (conversation_id,),
        ) as cur:
            row = await cur.fetchone()
            return row[0] if row else "default"
    except Exception as exc:
        logger.warning("_resolve_owner_id failed, using default: %s", exc)
        return "default"
