"""
Enrichment credit bucket endpoints for dashboard display.

Provides visibility into credit bucket balances, expiration dates,
and FEFO (First-Expiring-First-Out) consumption order.
"""

import logging
from datetime import date, datetime, timedelta
from typing import List

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from ...auth_core import get_current_identity
from ...config.enrichment import ENRICHMENT_ENABLED
from ...db import get_session as get_db
from ...models import EnrichmentCreditBucket


def require_enrichment_enabled():
    if not ENRICHMENT_ENABLED:
        raise HTTPException(
            status_code=404,
            detail="Enrichment features are not currently available",
        )


router = APIRouter(
    prefix="/api/v2/enrichments",
    tags=["enrichments"],
    dependencies=[Depends(require_enrichment_enabled)],
)
log = logging.getLogger(__name__)


# ============================================
# Response Models
# ============================================


class BucketResponse(BaseModel):
    """Credit bucket information for dashboard display."""

    source: str  # "tier" | "rollover" | "pack"
    expires_at: str  # ISO date string
    quantity_remaining: int
    quantity_total: int
    is_expiring_soon: bool  # True if expires in <= 7 days
    days_until_expiry: int


# ============================================
# Helper Functions
# ============================================


def _calculate_days_until_expiry(expires_at: datetime, today: date) -> int:
    """Calculate days until bucket expiration."""
    # Convert expires_at to date for comparison
    expiry_date = expires_at.date() if isinstance(expires_at, datetime) else expires_at
    return (expiry_date - today).days


def _determine_display_source(bucket: EnrichmentCreditBucket, today: date) -> str:
    """
    Determine display source for bucket.

    Tier credits that expire before end of current month are shown as "rollover"
    to indicate they rolled over from the previous billing period.
    """
    if bucket.source != "tier":
        return bucket.source

    # Check if tier bucket expires before end of current month
    end_of_month = (
        date(today.year, today.month + 1, 1)
        if today.month < 12
        else date(today.year + 1, 1, 1)
    )
    end_of_month = end_of_month - timedelta(days=1)  # Last day of current month

    expiry_date = (
        bucket.expires_at.date()
        if isinstance(bucket.expires_at, datetime)
        else bucket.expires_at
    )

    if expiry_date < end_of_month:
        return "rollover"

    return "tier"


# ============================================
# Endpoints
# ============================================


@router.get("/buckets", response_model=List[BucketResponse])
async def get_enrichment_buckets(
    identity: dict = Depends(get_current_identity), db: AsyncSession = Depends(get_db)
):
    """
    Get active enrichment credit buckets for dashboard display.

    Returns credit buckets ordered by expiration date (FEFO - First Expiring First Out).

    **Authorization**: Requires Clerk JWT with org_id

    **Response**:
    - Returns list of active buckets with remaining credits
    - Buckets ordered by expires_at ASC
    - Each bucket includes:
      - source: tier/rollover/pack
      - expires_at: ISO date string
      - quantity_remaining: credits available
      - quantity_total: original credit amount
      - is_expiring_soon: true if expires within 7 days
      - days_until_expiry: days until expiration

    **Error Codes**:
    - 400: Missing organization context in token
    - 401: Invalid or missing authentication token
    """
    account_id = identity.get("org_id")
    if not account_id:
        log.warning("[ENRICHMENT_BUCKETS] Request missing org_id in token")
        raise HTTPException(400, "No organization context in token")

    log.info(f"[ENRICHMENT_BUCKETS] Fetching buckets for account={account_id}")

    # Query active buckets with remaining credits
    result = await db.execute(
        select(EnrichmentCreditBucket)
        .where(EnrichmentCreditBucket.account_id == account_id)
        .where(EnrichmentCreditBucket.status == "active")
        .where(EnrichmentCreditBucket.quantity_remaining > 0)
        .order_by(EnrichmentCreditBucket.expires_at.asc())
    )
    buckets = result.scalars().all()

    log.info(
        f"[ENRICHMENT_BUCKETS] Found {len(buckets)} active buckets "
        f"for account={account_id}"
    )

    # Transform to response format
    today = date.today()
    response = []

    for bucket in buckets:
        days_until_expiry = _calculate_days_until_expiry(bucket.expires_at, today)
        is_expiring_soon = days_until_expiry <= 7
        display_source = _determine_display_source(bucket, today)

        # Convert expires_at to ISO string
        if isinstance(bucket.expires_at, datetime):
            expires_at_iso = bucket.expires_at.date().isoformat()
        else:
            expires_at_iso = bucket.expires_at.isoformat()

        response.append(
            BucketResponse(
                source=display_source,
                expires_at=expires_at_iso,
                quantity_remaining=bucket.quantity_remaining,
                quantity_total=bucket.quantity_total,
                is_expiring_soon=is_expiring_soon,
                days_until_expiry=days_until_expiry,
            )
        )

        log.debug(
            f"[ENRICHMENT_BUCKETS] Bucket: source={display_source} "
            f"remaining={bucket.quantity_remaining}/{bucket.quantity_total} "
            f"expires_at={expires_at_iso} days_left={days_until_expiry}"
        )

    if not response:
        log.info(
            f"[ENRICHMENT_BUCKETS] No active buckets found for account={account_id}"
        )

    return response
