from telegram import InlineKeyboardMarkup, InlineKeyboardButton from database import get_participants, get_active_raffles_in_channel, get_active_raffles, get_raffle_name from config import * def generate_raffle_selection_keyboard(channel_id): """Generates keyboard for users to select an active raffle in a channel.""" raffles = get_active_raffles_in_channel(channel_id) keyboard = [[InlineKeyboardButton(r["name"], callback_data=f"join:{r['id']}")] for r in raffles] return InlineKeyboardMarkup(keyboard) def generate_numbers_keyboard(raffle_id, user_id, page=0): """Generates the 10x10 number selection keyboard with status icons and paging.""" participants = get_participants(raffle_id) taken_numbers = {} user_reserved = set() user_taken = set() # Process participants to determine number statuses if participants: for participant in participants: participant_id = participant['user_id'] numbers = participant['numbers'] step = participant['step'] if numbers: # Ensure numbers is not None or empty try: numbers_set = {int(n) for n in numbers.split(',') if n.isdigit()} # Safer conversion if participant_id == user_id: if step == "waiting_for_payment": user_reserved.update(numbers_set) elif step == "completed": user_taken.update(numbers_set) for num in numbers_set: # Store only if not already taken by the current user (avoids overwriting user status) if num not in user_taken and num not in user_reserved: taken_numbers[num] = participant_id # Track who took it generally except ValueError: logging.warning(f"Invalid number format in participant data for raffle {raffle_id}: {numbers}") continue # Skip this participant's numbers if format is wrong # Build the keyboard grid keyboard = [] rows = 10 cols = 5 start = page * rows * cols end = start + rows * cols for i in range(rows): row_buttons = [] for j in range(cols): num = start + i * cols + j if num >= 100: # Ensure we don't go beyond 99 break num_str = f"{num:02}" # Determine icon based on status if num in user_taken: icon = "🟢" # Taken (Paid) by this user elif num in user_reserved: icon = "🔒" # Reserved (Not paid) by this user elif num in taken_numbers: # Check general taken status *after* specific user status icon = "❌" # Taken by someone else else: icon = "☑️" # Free row_buttons.append(InlineKeyboardButton(f"{icon} {num_str}", callback_data=f"number:{raffle_id}:{num}")) if row_buttons: # Only add row if it contains buttons keyboard.append(row_buttons) # Add Paging Buttons paging_buttons = [] if page > 0: paging_buttons.append(InlineKeyboardButton("⬅️ Anterior", callback_data=f"number:{raffle_id}:prev")) if end < 100: # Only show next if there are more numbers paging_buttons.append(InlineKeyboardButton("Siguiente ➡️", callback_data=f"number:{raffle_id}:next")) if paging_buttons: keyboard.append(paging_buttons) action_buttons_row = [ InlineKeyboardButton("✨ Número Aleatorio ✨", callback_data=f"random_num:{raffle_id}") ] keyboard.append(action_buttons_row) # Add Confirm/Cancel Buttons confirm_cancel_row = [ InlineKeyboardButton("👍 Confirmar Selección", callback_data=f"confirm:{raffle_id}"), InlineKeyboardButton("❌ Cancelar Selección", callback_data=f"cancel:{raffle_id}") ] keyboard.append(confirm_cancel_row) return InlineKeyboardMarkup(keyboard) # --- Admin Menu Keyboards --- def generate_admin_main_menu_keyboard(): keyboard = [ [InlineKeyboardButton("➕ Crear Nuevo Sorteo", callback_data=ADMIN_MENU_CREATE)], [InlineKeyboardButton("📋 Listar/Gestionar Sorteos", callback_data=ADMIN_MENU_LIST)], [InlineKeyboardButton("✏️ Editar Sorteo (Añadir Canales)", callback_data=ADMIN_EDIT_RAFFLE_SELECT)], # New option ] return InlineKeyboardMarkup(keyboard) def generate_channel_selection_keyboard_for_edit(existing_channel_ids, selected_new_channels_ids=None): """Generates channel selection keyboard for editing, excluding existing ones.""" if selected_new_channels_ids is None: selected_new_channels_ids = set() buttons = [] # CHANNELS is { 'alias': 'id' } for alias, channel_id_str in CHANNELS.items(): if channel_id_str not in existing_channel_ids: # Only show channels NOT already in the raffle text = f"✅ {alias}" if channel_id_str in selected_new_channels_ids else f"⬜️ {alias}" buttons.append([InlineKeyboardButton(text, callback_data=f"{SELECT_CHANNEL_PREFIX}{channel_id_str}")]) if selected_new_channels_ids: buttons.append([InlineKeyboardButton("➡️ Continuar con precios", callback_data=f"{SELECT_CHANNEL_PREFIX}done")]) buttons.append([InlineKeyboardButton("❌ Cancelar Edición", callback_data=f"{SELECT_CHANNEL_PREFIX}cancel_edit")]) return InlineKeyboardMarkup(buttons) def generate_admin_list_raffles_keyboard(): """Generates keyboard listing active raffles with management buttons.""" active_raffles = get_active_raffles() keyboard = [] if not active_raffles: keyboard.append([InlineKeyboardButton("No hay sorteos activos.", callback_data=ADMIN_NO_OP)]) else: for raffle in active_raffles: raffle_id = raffle['id'] raffle_name = raffle['name'] # Row for each raffle: Name Button (View Details), Announce Button, End Button keyboard.append([ InlineKeyboardButton(f"ℹ️ {raffle_name}", callback_data=f"{ADMIN_VIEW_RAFFLE_PREFIX}{raffle_id}"), InlineKeyboardButton("📢 Anunciar", callback_data=f"{ADMIN_ANNOUNCE_RAFFLE_PREFIX}{raffle_id}"), InlineKeyboardButton("🏁 Terminar", callback_data=f"{ADMIN_END_RAFFLE_PROMPT_PREFIX}{raffle_id}") ]) keyboard.append([InlineKeyboardButton("⬅️ Volver al Menú Principal", callback_data=ADMIN_MENU_BACK_MAIN)]) return InlineKeyboardMarkup(keyboard) def generate_admin_raffle_details_keyboard(raffle_id): """Generates keyboard for the raffle detail view.""" keyboard = [ # Add relevant actions here if needed later, e.g., edit description? [InlineKeyboardButton("📢 Anunciar de Nuevo", callback_data=f"{ADMIN_ANNOUNCE_RAFFLE_PREFIX}{raffle_id}")], [InlineKeyboardButton("🏁 Terminar Sorteo", callback_data=f"{ADMIN_END_RAFFLE_PROMPT_PREFIX}{raffle_id}")], [InlineKeyboardButton("⬅️ Volver a la Lista", callback_data=ADMIN_MENU_LIST)] # Back to list view ] return InlineKeyboardMarkup(keyboard) def generate_admin_cancel_end_keyboard(): """Generates a simple cancel button during the end process.""" keyboard = [ [InlineKeyboardButton("❌ Cancelar Finalización", callback_data=ADMIN_CANCEL_END_PROCESS)] ] return InlineKeyboardMarkup(keyboard) # --- Keyboards for Raffle Creation Conversation --- def generate_channel_selection_keyboard(selected_channels_ids=None): """Generates keyboard for admin to select target channels.""" if selected_channels_ids is None: selected_channels_ids = set() buttons = [] for alias, channel_id in CHANNELS.items(): # Mark selected channels text = f"✅ {alias}" if channel_id in selected_channels_ids else f"⬜️ {alias}" buttons.append([InlineKeyboardButton(text, callback_data=f"{SELECT_CHANNEL_PREFIX}{channel_id}")]) # Add Done button only if at least one channel is selected if selected_channels_ids: buttons.append([InlineKeyboardButton("➡️ Continuar", callback_data=f"{SELECT_CHANNEL_PREFIX}done")]) buttons.append([InlineKeyboardButton("❌ Cancelar Creación", callback_data=f"{SELECT_CHANNEL_PREFIX}cancel")]) return InlineKeyboardMarkup(buttons) def generate_confirmation_keyboard(): """Generates Yes/No keyboard for final confirmation.""" keyboard = [ [ InlineKeyboardButton("✅ Sí, crear sorteo", callback_data=CONFIRM_CREATION_CALLBACK), InlineKeyboardButton("❌ No, cancelar", callback_data=CANCEL_CREATION_CALLBACK), ] ] return InlineKeyboardMarkup(keyboard)