from __future__ import annotations

import uuid
from datetime import datetime, timedelta, timezone

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

from api.models.suggestion import (
    OPEN_SUGGESTION_STAGES,
    Suggestion,
    SuggestionRelevanceBump,
    SuggestionStage,
)

DEBOUNCE_SECONDS = 3600


async def bump_relevance(
    session: AsyncSession,
    suggestion: Suggestion,
    *,
    source: str,
    source_key: str,
    reason: str | None = None,
) -> bool:
    """Increment relevance when a suggestion is needed-but-unmet.

    Returns True when the counter was incremented, False when debounced.
    """
    if suggestion.stage not in OPEN_SUGGESTION_STAGES:
        return False

    cutoff = datetime.now(tz=timezone.utc) - timedelta(seconds=DEBOUNCE_SECONDS)
    existing = (
        await session.execute(
            select(SuggestionRelevanceBump.id)
            .where(SuggestionRelevanceBump.suggestion_id == suggestion.id)
            .where(SuggestionRelevanceBump.source == source)
            .where(SuggestionRelevanceBump.source_key == source_key)
            .where(SuggestionRelevanceBump.created_at >= cutoff)
            .limit(1)
        )
    ).scalar_one_or_none()
    if existing is not None:
        return False

    now = datetime.now(tz=timezone.utc)
    suggestion.relevance += 1
    suggestion.relevance_events += 1
    suggestion.last_requested_at = now
    session.add(
        SuggestionRelevanceBump(
            suggestion_id=suggestion.id,
            source=source,
            source_key=source_key,
            reason=reason,
        )
    )
    return True


async def bump_matching_for_capability_request(
    session: AsyncSession,
    *,
    request_id: uuid.UUID,
    title: str,
    description: str,
    capability_type: str,
    catalog_entry_id: uuid.UUID | None = None,
) -> int:
    """Bump open suggestions that match an unfulfilled capability need."""
    rows = (
        await session.execute(
            select(Suggestion).where(Suggestion.stage.in_(OPEN_SUGGESTION_STAGES))
        )
    ).scalars().all()

    haystack = f"{title} {description} {capability_type}".lower()
    bumped = 0
    for suggestion in rows:
        matched = False
        if suggestion.origin_ref:
            ref = suggestion.origin_ref.lower()
            if ref in haystack or any(token in haystack for token in ref.split("-") if len(token) > 4):
                matched = True
        if not matched and suggestion.title.lower() in haystack:
            matched = True
        if not matched:
            continue
        if await bump_relevance(
            session,
            suggestion,
            source="capability_request",
            source_key=str(request_id),
            reason=f"Capability request matched: {title}",
        ):
            bumped += 1
    return bumped


async def bump_suggestions_for_next_steps(
    session: AsyncSession,
    suggestions: list[Suggestion],
) -> int:
    """Bump only suggestions surfaced in a next-steps response."""
    bucket = datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H")
    bumped = 0
    for suggestion in suggestions:
        if await bump_relevance(
            session,
            suggestion,
            source="next_steps",
            source_key=bucket,
            reason="Surfaced during get_next_steps lookup",
        ):
            bumped += 1
    return bumped