"""
Credit Management Service
Handles enrichment credit consumption with "purchased-first" logic.

Credit Consumption Order:
1. Purchased credits (one-time purchases, never expire)
2. Monthly subscription credits (reset monthly)

This ensures users get value from their one-time purchases before consuming
renewable monthly credits.
"""

from typing import Dict, Tuple
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update
import logging

from ..models import Account
from ..middleware.quota_checker import get_quota, record_quota_usage

log = logging.getLogger(__name__)


async def get_credit_balance(account_id: str, db: AsyncSession) -> Dict[str, int]:
    """
    Get detailed credit balance breakdown.

    Returns:
        dict with:
        - purchased: Purchased credits remaining (never expire)
        - monthly: Monthly subscription credits remaining (reset monthly)
        - monthly_limit: Total monthly credits from subscription
        - total: Total available credits (purchased + monthly)
    """
    # Get account for purchased credits
    result = await db.execute(select(Account).where(Account.id == account_id))
    account = result.scalar_one_or_none()

    if not account:
        raise ValueError(f"Account {account_id} not found")

    # Get quota for monthly credits
    quota = await get_quota(account_id, db)
    limits = quota.get_limits()

    purchased_credits = getattr(account, "purchased_credits", 0)
    monthly_limit = limits["enrichment_credits"]
    monthly_used = quota.enrichment_credits_used
    monthly_remaining = max(0, monthly_limit - monthly_used)

    return {
        "purchased": purchased_credits,
        "monthly": monthly_remaining,
        "monthly_limit": monthly_limit,
        "monthly_used": monthly_used,
        "total": purchased_credits + monthly_remaining,
    }


async def consume_credits(
    account_id: str, credits_needed: int, db: AsyncSession
) -> Dict[str, int]:
    """
    Consume credits with purchased-first logic.

    Args:
        account_id: Account to consume credits from
        credits_needed: Number of credits to consume
        db: Database session

    Returns:
        dict with:
        - consumed_from_purchased: Credits consumed from purchased
        - consumed_from_monthly: Credits consumed from monthly
        - remaining_purchased: Purchased credits after consumption
        - remaining_monthly: Monthly credits after consumption

    Raises:
        ValueError: If insufficient credits available
    """
    # Get current balance
    balance = await get_credit_balance(account_id, db)

    total_available = balance["total"]
    if credits_needed > total_available:
        raise ValueError(
            f"Insufficient credits. Need {credits_needed}, have {total_available} "
            f"({balance['purchased']} purchased + {balance['monthly']} monthly)"
        )

    # Consume purchased credits first
    consumed_from_purchased = min(credits_needed, balance["purchased"])
    remaining_needed = credits_needed - consumed_from_purchased

    # Then consume monthly credits
    consumed_from_monthly = min(remaining_needed, balance["monthly"])

    # Update purchased credits in Account table
    if consumed_from_purchased > 0:
        await db.execute(
            update(Account)
            .where(Account.id == account_id)
            .values(
                purchased_credits=Account.purchased_credits - consumed_from_purchased
            )
        )

    # Update monthly credits in quota tracker
    if consumed_from_monthly > 0:
        await record_quota_usage(
            account_id=account_id,
            db=db,
            rows_returned=0,  # Don't count rows, just credits
            credits_consumed=consumed_from_monthly,
            used_grace=False,
        )

    await db.commit()

    log.info(
        f"Account {account_id} consumed {credits_needed} credits: "
        f"{consumed_from_purchased} purchased, {consumed_from_monthly} monthly"
    )

    return {
        "consumed_from_purchased": consumed_from_purchased,
        "consumed_from_monthly": consumed_from_monthly,
        "remaining_purchased": balance["purchased"] - consumed_from_purchased,
        "remaining_monthly": balance["monthly"] - consumed_from_monthly,
    }


async def add_purchased_credits(
    account_id: str, credits: int, db: AsyncSession, reason: str = "purchase"
) -> int:
    """
    Add purchased credits to an account.

    Args:
        account_id: Account to add credits to
        credits: Number of credits to add
        db: Database session
        reason: Reason for credit addition (for logging)

    Returns:
        New total purchased credits balance
    """
    result = await db.execute(select(Account).where(Account.id == account_id))
    account = result.scalar_one_or_none()

    if not account:
        raise ValueError(f"Account {account_id} not found")

    new_balance = getattr(account, "purchased_credits", 0) + credits

    await db.execute(
        update(Account)
        .where(Account.id == account_id)
        .values(purchased_credits=new_balance)
    )
    await db.commit()

    log.info(
        f"Added {credits} purchased credits to account {account_id}. "
        f"Reason: {reason}. New balance: {new_balance}"
    )

    return new_balance


async def check_sufficient_credits(
    account_id: str, credits_needed: int, db: AsyncSession
) -> Tuple[bool, Dict[str, int]]:
    """
    Check if account has sufficient credits without consuming them.

    Args:
        account_id: Account to check
        credits_needed: Number of credits needed
        db: Database session

    Returns:
        (has_enough: bool, balance: dict)
    """
    balance = await get_credit_balance(account_id, db)
    has_enough = balance["total"] >= credits_needed

    return has_enough, balance
