import logging import aiosqlite from datetime import datetime ,timezone from typing import Optional ,Dict ,Callable ,Any ,Tuple from aiogram import Bot from config .settings import Settings from db .database import get_promo_code_by_code ,increment_promo_activation ,get_db_connection_manager ,_setup_db_connection from .subscription_service import SubscriptionService from bot .middlewares .i18n import JsonI18n class PromoCodeService : def __init__ ( self , db_conn_provider :Callable [[],Any ], settings :Settings , subscription_service :SubscriptionService , bot :Bot , i18n :JsonI18n ): self .db_conn_provider =db_conn_provider self .settings =settings self .subscription_service =subscription_service self .bot =bot self .i18n =i18n async def apply_promo_code (self ,user_id :int ,code_input :str ,user_lang :str )->Tuple [bool ,str ]: """ Applies a promo code for a user. Returns: (success_status: bool, message_text_for_user: str) """ _ =lambda k ,**kw :self .i18n .gettext (user_lang ,k ,**kw ) code_input_upper =code_input .strip ().upper () async with self .db_conn_provider ()as db : await _setup_db_connection (db ) try : promo_data =await get_promo_code_by_code (code_input_upper ,db_conn =db ) if not promo_data : return False ,_ ("promo_code_not_found",code =code_input_upper ) if promo_data ['current_activations']>=promo_data ['max_activations']: return False ,_ ("promo_code_max_activations_reached",code =code_input_upper ) active_sub =await self .subscription_service .get_active_subscription (user_id ) if not active_sub : return False ,_ ("promo_code_no_active_subscription") bonus_days =promo_data ['bonus_days'] new_end_date =await self .subscription_service .extend_active_subscription_days ( user_id =user_id , bonus_days =bonus_days , db_conn =db , reason =f"promo code {code_input_upper}" ) if new_end_date : activation_success =await increment_promo_activation (promo_data ['promo_code_id'],user_id ,db_conn =db ,payment_id =None ) if activation_success : await db .commit () return True ,_ ("promo_code_applied_success", code =code_input_upper , bonus_days =bonus_days , new_end_date =new_end_date .strftime ('%Y-%m-%d')) else : await db .rollback () return False ,_ ("promo_code_invalid_or_expired") else : await db .rollback () return False ,_ ("error_applying_promo_bonus") except Exception as e : logging .error (f"Error applying promo code {code_input_upper} for user {user_id}: {e}",exc_info =True ) await db .rollback () return False ,_ ("error_try_again")