"""
Credit manager for subscription credit tracking.

Uses the AiVibe platform API (api.aivibe.cloud) for atomic credit deduction.
All credit data is stored in PostgreSQL at db.aivibe.cloud.
Admin status and credits come from the platform API — no hardcoded bypasses.
"""

from __future__ import annotations

import threading
from typing import TYPE_CHECKING

from aicippy.billing.models import CreditTransaction
from aicippy.utils.async_utils import run_sync
from aicippy.utils.logging import get_logger

if TYPE_CHECKING:
    from aicippy.billing.plan_validator import PlanValidator
    from aicippy.platform.client import PlatformClient

logger = get_logger(__name__)


class CreditManager:
    """Manages credit checking and deduction for AiCippy usage.

    Uses the platform API (api.aivibe.cloud) for atomic credit operations.
    All data stored in PostgreSQL (db.aivibe.cloud, aicippy_com_* tables).
    Admin status comes from the platform API is_admin field.

    Args:
        plan_validator: PlanValidator instance for plan lookups.
        platform_client: PlatformClient for api.aivibe.cloud operations.
    """

    def __init__(
        self,
        plan_validator: PlanValidator,
        platform_client: PlatformClient,
    ) -> None:
        from aicippy.config import get_settings

        self._validator = plan_validator
        self._platform_client = platform_client
        settings = get_settings()
        self._credits_per_invocation = settings.credits_per_invocation
        self._session_credits_used: int = 0
        self._session_lock = threading.Lock()

    def check_credits(self, email: str) -> tuple[bool, int]:
        """Check if the user has sufficient credits.

        All users (including admin) have real credit balances that are
        checked and deducted via the platform API.

        Args:
            email: User email address.

        Returns:
            Tuple of (has_credits, remaining_count).
        """
        plan_info = self._validator.validate_or_cached(email)

        has_credits = plan_info.credits_remaining >= self._credits_per_invocation
        return has_credits, plan_info.credits_remaining

    def deduct_credit(self, email: str, action: str = "aicippy_chat") -> CreditTransaction:
        """Deduct credits for an AiCippy invocation via platform API.

        Admin users (determined by platform is_admin) track usage locally
        but are not credit-gated. Regular users go through platform API
        for atomic credit deduction.

        Args:
            email: User email address.
            action: Description of the action consuming credits.

        Returns:
            CreditTransaction with result details.
        """
        plan_info = self._validator.validate_or_cached(email)

        if not plan_info.tenant_id:
            return CreditTransaction(
                success=False,
                credits_remaining=0,
                error="No tenant found for credit deduction",
            )

        try:
            result = run_sync(
                self._platform_client.deduct_credits(
                    tenant_id=plan_info.tenant_id,
                    amount=self._credits_per_invocation,
                    source="aicippy",
                    description=action,
                )
            )

            success = result.get("success", False)
            if success:
                self._validator.clear_cache()
                with self._session_lock:
                    self._session_credits_used += self._credits_per_invocation

                logger.info(
                    "credit_deducted",
                    tenant_id=plan_info.tenant_id,
                    amount=self._credits_per_invocation,
                    remaining=result.get("credits_remaining", 0),
                    action=action,
                    transaction_id=result.get("transaction_id"),
                )

            return CreditTransaction(
                success=success,
                credits_remaining=int(result.get("credits_remaining", 0)),
                transaction_id=result.get("transaction_id"),
                error=result.get("error"),
            )

        except Exception as e:
            logger.exception(
                "credit_deduction_platform_error",
                tenant_id=plan_info.tenant_id,
                error=str(e),
            )
            return CreditTransaction(
                success=False,
                credits_remaining=plan_info.credits_remaining,
                error=f"Credit deduction failed: {e}",
            )

    async def check_credits_async(self, email: str) -> tuple[bool, int]:
        """Check if the user has sufficient credits (async version).

        All users (including admin) have real credit balances.

        Args:
            email: User email address.

        Returns:
            Tuple of (has_credits, remaining_count).
        """
        plan_info = await self._validator.validate_or_cached_async(email)

        has_credits = plan_info.credits_remaining >= self._credits_per_invocation
        return has_credits, plan_info.credits_remaining

    async def deduct_credit_async(
        self, email: str, action: str = "aicippy_chat"
    ) -> CreditTransaction:
        """Deduct credits for an AiCippy invocation via platform API (async version).

        Use from async contexts to avoid event loop conflicts.

        Args:
            email: User email address.
            action: Description of the action consuming credits.

        Returns:
            CreditTransaction with result details.
        """
        plan_info = await self._validator.validate_or_cached_async(email)

        if not plan_info.tenant_id:
            return CreditTransaction(
                success=False,
                credits_remaining=0,
                error="No tenant found for credit deduction",
            )

        try:
            result = await self._platform_client.deduct_credits(
                tenant_id=plan_info.tenant_id,
                amount=self._credits_per_invocation,
                source="aicippy",
                description=action,
            )

            success = result.get("success", False)
            if success:
                self._validator.clear_cache()
                with self._session_lock:
                    self._session_credits_used += self._credits_per_invocation

                logger.info(
                    "credit_deducted",
                    tenant_id=plan_info.tenant_id,
                    amount=self._credits_per_invocation,
                    remaining=result.get("credits_remaining", 0),
                    action=action,
                    transaction_id=result.get("transaction_id"),
                )

            return CreditTransaction(
                success=success,
                credits_remaining=int(result.get("credits_remaining", 0)),
                transaction_id=result.get("transaction_id"),
                error=result.get("error"),
            )

        except Exception as e:
            logger.exception(
                "credit_deduction_platform_error",
                tenant_id=plan_info.tenant_id,
                error=str(e),
            )
            return CreditTransaction(
                success=False,
                credits_remaining=plan_info.credits_remaining,
                error=f"Credit deduction failed: {e}",
            )

    @property
    def session_credits_used(self) -> int:
        """Total credits used in this session."""
        with self._session_lock:
            return self._session_credits_used

    def get_remaining_credits(self, email: str) -> int:
        """Get the current remaining credit count from the platform API."""
        plan_info = self._validator.validate_or_cached(email)
        return plan_info.credits_remaining
