
import logging
import asyncio
import os
import sys
import tempfile
import re
from datetime import datetime
from aiogram import Router, F, Bot
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, FSInputFile
from config import ADMIN_IDS, LOG_GROUP_ID
from db import db
from utils.helpers import check_membership_and_notify

logger = logging.getLogger(__name__)

router = Router()

@router.message(Command("puan2mass"))
async def cmd_puan2_mass(message: Message, bot: Bot):
    """PUAN2 Mass Check command using multi-worker script"""
    try:
        # Check membership first
        if not await check_membership_and_notify(message):
            return

        # Parse command
        command_text = message.text.strip()
        lines = command_text.split('\n')

        if len(lines) < 2:
            await message.answer(
                "❌ INVALID FORMAT\n\n"
                "Usage: /puan2mass followed by cards (one per line)\n\n"
                "Example:\n"
                "/puan2mass\n"
                "5526080000000006|12|2028|123\n"
                "5526080000000007|12|2028|123\n"
                "5526080000000008|12|2028|123"
            )
            return

        # Extract cards (skip first line which is the command)
        cards = []
        for line in lines[1:]:
            line = line.strip()
            # Simple validation: at least 15 chars and contains pipes
            if len(line) > 15 and '|' in line:
                cards.append(line)

        if not cards:
            await message.answer("❌ No valid cards found. Format: CARD|MM|YY|CVV")
            return

        # Check minimum card requirement (3 cards)
        if len(cards) < 3:
            await message.answer(f"❌ Minimum 3 cards required. You provided {len(cards)} card(s).")
            return

        # Check card limit (max 50 cards per request)
        if len(cards) > 50:
            await message.answer(f"❌ Maximum 50 cards allowed per request. You provided {len(cards)} cards.")
            return

        # Get user chat ID
        chat_id = message.from_user.id

        # Check total puan limit
        current_limit = await db.get_user_limit(chat_id, 'puanlimit')
        if current_limit < len(cards):
            await message.answer(f"❌ Not enough Puan limit. Need {len(cards)}, have {current_limit}")
            return

        # Send initial message
        status_msg = await message.reply(
            f"𝐏𝐔𝐀𝐍𝟐 𝐌𝐀𝐒𝐒 𝐒𝐓𝐀𝐑𝐓𝐄𝐃 🚀\n\n"
            f"Processing {len(cards)} cards using 6 workers...\n"
            f"Please wait..."
        )

        # Create temporary file for cards
        with tempfile.NamedTemporaryFile(mode='w+', delete=False, suffix='.txt', encoding='utf-8') as temp:
            temp.write("\n".join(cards))
            temp_file_path = temp.name

        # Prepare environment variables
        env = os.environ.copy()
        session_id = str(int(datetime.now().timestamp()))
        env['PUAN2_USER_ID'] = str(chat_id)
        env['PUAN2_SESSION_ID'] = session_id
        env['PUAN2_WORKERS'] = "1,2,3,4,5,6" # Use all 6 workers

        # Defines paths
        # We need absolute path to puan2_multiworker.py
        # Assuming it's in the root of the checker bot workspace
        script_path = os.path.join(os.getcwd(), 'puan2_multiworker.py')
        
        # Results and progress files (matching those in puan2_multiworker.py)
        results_file = f'puan2_multiworker_results_{chat_id}_s{session_id}.txt'
        progress_file = f'puan2_multiworker_progress_{chat_id}_s{session_id}.txt'

        # Start subprocess
        process = await asyncio.create_subprocess_exec(
            sys.executable, script_path, temp_file_path,
            env=env,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        
        # Monitor progress
        last_update_time = 0
        update_interval = 2.0 # Update every 2 seconds
        
        start_time = datetime.now()
        
        while process.returncode is None:
            await asyncio.sleep(1) # Check every second
            
            # Read progress file if exists
            if os.path.exists(progress_file):
                try:
                    with open(progress_file, 'r', encoding='utf-8') as f:
                        content = f.read().strip()
                        if content:
                            parts = content.split('|')
                            if len(parts) >= 5:
                                completed, total, approved, declined, errors = parts
                                
                                # Only update message if interval passed
                                if (datetime.now().timestamp() - last_update_time) > update_interval:
                                    elapsed = int((datetime.now() - start_time).total_seconds())
                                    
                                    # Calculate approx speed
                                    completed_int = int(completed)
                                    speed = f"{completed_int/elapsed:.1f}/s" if elapsed > 0 else "0.0/s"
                                    
                                    progress_text = (
                                        f"𝐏𝐔𝐀𝐍𝟐 𝐌𝐀𝐒𝐒 𝐑𝐔𝐍𝐍𝐈𝐍𝐆 🔄\n\n"
                                        f"Processed: {completed}/{total}\n"
                                        f"✅ Approved: {approved}\n"
                                        f"❌ Declined: {declined}\n"
                                        f"⚠️ Errors: {errors}\n\n"
                                        f"⏱ Time: {elapsed}s | ⚡️ Speed: {speed}"
                                    )
                                    
                                    try:
                                        await status_msg.edit_text(progress_text)
                                        last_update_time = datetime.now().timestamp()
                                    except:
                                        pass
                except Exception as e:
                    logger.error(f"Error reading progress file: {e}")

            # Check if process finished
            if process.returncode is not None:
                break
                
            # Wait for process to finish if it's done quickly or just to check status
            try:
                # Use wait_for with a small timeout to not block loop
                await asyncio.wait_for(process.wait(), timeout=0.1)
            except asyncio.TimeoutError:
                pass
        
        # Process finished
        results_out = ""
        
        # Read final results
        final_approved = 0
        final_declined = 0
        final_errors = 0
        processed_cards = set()

        if os.path.exists(results_file):
            try:
                with open(results_file, 'r', encoding='utf-8') as f:
                    results_lines = f.readlines()
                    
                formatted_results = []
                for line in results_lines:
                    line = line.strip()
                    if not line: continue
                    
                    # Robust parsing using rpartition to handle "CARD | STATUS | MSG"
                    # We work from right to left
                    # 1. Split Message
                    temp, sep1, msg_clean = line.rpartition(' | ')
                    if sep1:
                        # 2. Split Status
                        card_raw, sep2, status_clean = temp.rpartition(' | ')
                        if sep2:
                            card_clean = card_raw.strip()
                            status_clean = status_clean.strip()
                            msg_clean = msg_clean.strip()
                            
                            # Add normalized card to processed set
                            processed_cards.add(card_clean.replace(" ", ""))
                            
                            if 'APPROVED' in status_clean:
                                formatted_results.append(f"{card_clean} | ✅ {msg_clean}")
                                final_approved += 1
                            else:
                                formatted_results.append(f"{card_clean} | ❌ {msg_clean}")
                                final_declined += 1
                        else:
                            # Format error (missing status separator)
                            logger.warning(f"Malformed result line (no status sep): {line}")
                            # Try to salvage if possible or just skip
                    else:
                         # Format error (no message sep)
                         logger.warning(f"Malformed result line (no msg sep): {line}")
                
                # Check for missing cards (timeouts/crashes)
                # Normalize input cards too
                for card in cards:
                     card_norm = card.strip().replace(" ", "")
                     if card_norm not in processed_cards:
                         formatted_results.append(f"{card.strip()} | ⚠️ Error/Timeout")
                         final_errors += 1

                results_out = "\n".join(formatted_results)
            except Exception as e:
                logger.error(f"Error reading results file: {e}")
                results_out = "Error reading results."
        else:
             results_out = "❌ Fatal Error: No results file created."

        # Deduct total cards count from limit
        # We deduct for all attempts even if failed/timeout
        await db.decrement_limit_bulk(chat_id, 'puanlimit', len(cards))
        new_limit = await db.get_user_limit(chat_id, 'puanlimit')

        # Final message
        final_header = f"𝐏𝐔𝐀𝐍𝟐 𝐌𝐀𝐒𝐒 𝐂𝐎𝐌𝐏𝐋𝐄𝐓𝐄𝐃 ✅\n\n"
        final_footer = f"\n\n✅ 𝐋𝐈𝐕𝐄: {final_approved} | ❌ 𝐃𝐄𝐂𝐋𝐈𝐍𝐄𝐃: {final_declined} | ⚠️ 𝐄𝐑𝐑𝐎𝐑: {final_errors}\n"
        final_footer += f"Remaining Limit: {new_limit}\n"
        final_footer += f"By @aerithiacheck3r_bot"
        
        full_msg = final_header + results_out + final_footer
        
        # If message is too long, send as file
        if len(full_msg) > 4000:
            with open("results.txt", "w", encoding="utf-8") as f:
                f.write(full_msg)
            await message.reply_document(FSInputFile("results.txt"), caption=final_footer)
            os.remove("results.txt")
        else:
            try:
                await status_msg.edit_text(full_msg)
            except Exception as e:
                logger.error(f"Failed to edit final message: {e}")
                await message.answer(full_msg)

        # Log to admin group
        if chat_id not in ADMIN_IDS:
            try:
                username = message.from_user.username or message.from_user.first_name
                log_msg = f"🚦 @{username} ({chat_id}) puan2mass yaptı.\n{final_footer}"
                await bot.send_message(LOG_GROUP_ID, log_msg)
            except Exception as e:
                logger.error(f"Failed to log to group: {e}")

        # Cleanup temp files
        try:
            os.remove(temp_file_path)
            if os.path.exists(results_file): os.remove(results_file)
            if os.path.exists(progress_file): os.remove(progress_file)
        except:
            pass

    except Exception as e:
        logger.error(f"Error in cmd_puan2_mass: {e}")
        await message.reply(f"❌ An error occurred: {str(e)}")

