import discord
from discord import app_commands
from discord.ext import commands
from datetime import datetime, timedelta, timezone
import logging
import config
from database import db, InsufficientFunds, DuplicateTransaction, UserBanned
from utils.security import check_security_compliance
from utils.logger import log_suspicious_activity, log_transaction, send_embed_to_channel

logger = logging.getLogger("gamble_bot.cogs.economy")

from web_server import send_minecraft_payout

# Core function to execute payouts via the Minecraft Client bot bridge
async def execute_game_transfer(tx_id: int, username: str, amount: float) -> tuple[bool, str]:
    """
    Sends the payout request to the Minecraft client bot over WebSocket.
    Returns (success: bool, reason: str)
    """
    logger.info(f"[GAME API] Processing withdrawal payout: {amount} to '{username}' (TX ID: {tx_id})...")
    success, reason = await send_minecraft_payout(tx_id, username, amount)
    if not success:
        logger.error(f"In-game transfer failed: {reason}")
    return success, reason


class DepositModal(discord.ui.Modal, title="Para Yatırma Talebi"):
    game_username = discord.ui.TextInput(
        label="Oyun İçi Kullanıcı Adınız",
        placeholder="Örn: KolicPlayer",
        min_length=3,
        max_length=100,
        required=True
    )
    tx_code = discord.ui.TextInput(
        label="İşlem Kodu / Ödeme ID'si",
        placeholder="Örn: TX-982348A",
        min_length=5,
        max_length=100,
        required=True
    )
    amount = discord.ui.TextInput(
        label="Yatırılan Miktar",
        placeholder="Örn: 5000",
        min_length=1,
        max_length=15,
        required=True
    )

    async def on_submit(self, interaction: discord.Interaction):
        # Prevent spam/bans
        if not await check_security_compliance(interaction):
            return

        # Validate amount
        try:
            val_amount = float(self.amount.value)
            if val_amount <= 0:
                raise ValueError()
        except ValueError:
            await interaction.response.send_message("❌ Hata: Lütfen geçerli, pozitif bir miktar girin.", ephemeral=True)
            return

        await interaction.response.defer(ephemeral=True)

        from web_server import pending_deposits
        code_input = self.tx_code.value.strip()

        if code_input not in pending_deposits:
            await interaction.followup.send(
                "❌ **Geçersiz İşlem Kodu!**\n"
                "Lütfen oyun içinde bota ödeme yaptıktan sonra size verilen kodu girdiğinizden emin olun.",
                ephemeral=True
            )
            return

        deposit_info = pending_deposits[code_input]
        expected_username = deposit_info["username"]
        expected_amount = deposit_info["amount"]

        if self.game_username.value.strip().lower() != expected_username.lower():
            await interaction.followup.send(
                f"❌ **Kullanıcı Adı Uyuşmuyor!**\n"
                f"İşlem koduna kayıtlı oyun içi ad: `{expected_username}` (Girdiğiniz: `{self.game_username.value}`)",
                ephemeral=True
            )
            return

        # Override user entered amount with actual paid amount to prevent fraud
        val_amount = expected_amount

        try:
            # Process deposit atomically
            new_balance = await db.process_deposit(
                discord_id=interaction.user.id,
                game_username=expected_username,
                transaction_code=code_input,
                amount=val_amount
            )
            
            # Consume/invalidate the code so it cannot be double-spent
            del pending_deposits[code_input]

            # Success response
            await interaction.followup.send(
                f"✅ **Yatırma Başarılı!**\n"
                f"Hesabınıza **{val_amount:,.2f}** birim bakiye eklendi.\n"
                f"Yeni Bakiyeniz: **{new_balance:,.2f}**",
                ephemeral=True
            )

            # Try to notify via DM
            try:
                dm_embed = discord.Embed(
                    title="💰 Bakiye Yüklendi!",
                    description=f"Oyun içi transferiniz doğrulanarak bakiye yüklemesi gerçekleştirildi.",
                    color=discord.Color.green(),
                    timestamp=datetime.utcnow()
                )
                dm_embed.add_field(name="Oyun Adı", value=self.game_username.value, inline=True)
                dm_embed.add_field(name="Yüklenen Tutar", value=f"{val_amount:,.2f} birim", inline=True)
                dm_embed.add_field(name="Yeni Bakiye", value=f"{new_balance:,.2f} birim", inline=True)
                dm_embed.add_field(name="İşlem Kodu", value=f"`{self.tx_code.value}`", inline=False)
                await interaction.user.send(embed=dm_embed)
            except discord.Forbidden:
                logger.warning(f"Failed to send DM to user {interaction.user.id}")

            # Admin log
            await log_transaction(
                bot=interaction.client,
                user=interaction.user,
                tx_type="deposit",
                amount=val_amount,
                status="completed",
                details=f"Oyun Adı: {self.game_username.value}\nİşlem Kodu: {self.tx_code.value}"
            )

        except DuplicateTransaction:
            await interaction.followup.send("❌ Bu işlem kodu veya ödeme ID'si sistemde zaten kayıtlı!", ephemeral=True)
            # Log as suspicious double spend attempt
            await log_suspicious_activity(
                interaction.client,
                interaction.user,
                "Double_Spend_Attempt",
                f"Aynı işlem kodu ile mükerrer deposit denemesi. Kod: {self.tx_code.value}, Miktar: {val_amount}"
            )
        except UserBanned:
            await interaction.followup.send("❌ Banlandığınız için bu işlemi gerçekleştiremezsiniz.", ephemeral=True)
        except Exception as e:
            logger.error(f"Error handling deposit modal: {e}", exc_info=True)
            await interaction.followup.send("❌ Beklenmeyen bir veritabanı hatası oluştu.", ephemeral=True)


class WithdrawModal(discord.ui.Modal):
    def __init__(self, default_username: str = ""):
        super().__init__(title="Para Çekme Talebi")
        self.game_username = discord.ui.TextInput(
            label="Oyun İçi Kullanıcı Adınız",
            placeholder="Örn: KolicPlayer",
            default=default_username or "",
            min_length=3,
            max_length=100,
            required=True
        )
        self.amount = discord.ui.TextInput(
            label="Çekilecek Miktar",
            placeholder="Örn: 2500",
            min_length=1,
            max_length=15,
            required=True
        )
        self.add_item(self.game_username)
        self.add_item(self.amount)

    async def on_submit(self, interaction: discord.Interaction):
        if not await check_security_compliance(interaction):
            return

        # Check linked account security
        user_db = await db.get_user(interaction.user.id)
        if not user_db or not user_db.get("game_username"):
            await interaction.response.send_message(
                "❌ **Güvenlik Engeli:** Önce hesabınızı bir Minecraft karakteriyle eşleştirmeniz gerekmektedir!\n"
                "Lütfen `#bakiye-islemleri` kanalındaki **🔗 Hesap Eşleştir** butonunu kullanın.",
                ephemeral=True
            )
            return

        linked_username = user_db["game_username"]
        typed_username = self.game_username.value.strip()

        if typed_username.lower() != linked_username.lower():
            await interaction.response.send_message(
                f"❌ **Güvenlik Engeli:** Sadece kendi eşleştirdiğiniz Minecraft hesabına para çekebilirsiniz!\n"
                f"Eşleşen hesabınız: **`{linked_username}`** (Girdiğiniz: `{typed_username}`)\n\n"
                f"*Eğer hesap değiştirmek istiyorsanız lütfen yetkililere bildirin.*",
                ephemeral=True
            )
            return

        # Validate amount
        from utils.security import parse_money_string
        val_amount = parse_money_string(self.amount.value)
        if val_amount <= 0:
            await interaction.response.send_message("❌ Hata: Lütfen geçerli, pozitif bir miktar girin (Örn: 100k, 5m, 1b).", ephemeral=True)
            return

        await interaction.response.defer(ephemeral=False)

        user_id = interaction.user.id
        username = linked_username

        try:
            from utils.security import format_money_string, schedule_message_delete
            
            # --- 1. HOURLY WITHDRAWAL VELOCITY / SMURFING DEFENSE ---
            one_hour_ago = datetime.utcnow() - timedelta(hours=1)
            if config.USE_SQLITE:
                recent_txs = await db.fetch(
                    "SELECT SUM(amount) as s FROM economy_transactions WHERE discord_id = ? AND type = 'withdraw' AND status IN ('completed', 'pending') AND created_at >= ?",
                    user_id, one_hour_ago.isoformat()
                )
            else:
                recent_txs = await db.fetch(
                    "SELECT SUM(amount) as s FROM economy_transactions WHERE discord_id = $1 AND type = 'withdraw' AND status IN ('completed', 'pending') AND created_at >= $2",
                    user_id, one_hour_ago
                )

            hourly_volume = float(recent_txs[0]["s"]) if recent_txs and recent_txs[0]["s"] else 0.0
            total_projected_volume = hourly_volume + val_amount
            is_smurfing_velocity = (val_amount < config.WITHDRAW_APPROVAL_LIMIT) and (total_projected_volume >= config.WITHDRAW_APPROVAL_LIMIT)

            # Check if single withdrawal OR 1-hour total volume exceeds approval limit
            if val_amount >= config.WITHDRAW_APPROVAL_LIMIT or is_smurfing_velocity:
                # Place in admin approval queue (balance is frozen during request)
                tx_id = await db.create_withdrawal_request(user_id, username, val_amount, "pending")
                
                if is_smurfing_velocity:
                    desc_text = (
                        f"{interaction.user.mention} (**{username}**) hesabından **{format_money_string(val_amount)}** çekmek için talep oluşturdu.\n\n"
                        f"⚠️ **Saatlik Hacim Güvenlik Kilidi:** Son 1 saatteki toplam çekim hacminiz (**{format_money_string(total_projected_volume)}**), "
                        f"güvenlik limiti olan **{format_money_string(config.WITHDRAW_APPROVAL_LIMIT)}** sınırını aştığı için işlem parça çekim koruması gereğince yetkili onayına yönlendirildi."
                    )
                    # Log suspicious smurfing attempt
                    await log_suspicious_activity(
                        interaction.client,
                        interaction.user,
                        "WITHDRAW_SMURFING_ATTEMPT",
                        f"Kullanıcı 1 saatte toplam {format_money_string(total_projected_volume)} tutarında parça çekim yapmaya çalıştı."
                    )
                else:
                    desc_text = (
                        f"{interaction.user.mention} (**{username}**) hesabından **{format_money_string(val_amount)}** çekmek için talep oluşturdu.\n\n"
                        f"İşlem tutarı limit (**{format_money_string(config.WITHDRAW_APPROVAL_LIMIT)}**) üzerinde olduğu için yetkili onayına gönderildi."
                    )

                msg = await interaction.followup.send(
                    embed=discord.Embed(
                        title="⌛ Para Çekme Talebi Onayda",
                        description=desc_text,
                        color=discord.Color.orange(),
                        timestamp=datetime.utcnow()
                    ),
                    ephemeral=False
                )
                import asyncio
                asyncio.create_task(schedule_message_delete(msg, 10.0))

                # Send approval ticket to Admin Approval Channel
                await self.send_approval_ticket(interaction, tx_id, user_id, username, val_amount, is_smurfing=is_smurfing_velocity, hourly_vol=total_projected_volume)
                
                # Admin log
                await log_transaction(
                    bot=interaction.client,
                    user=interaction.user,
                    tx_type="withdraw_pending",
                    amount=val_amount,
                    status="pending",
                    details=f"Yetkili Onayı Bekleniyor (Saatlik Toplam: {format_money_string(total_projected_volume)})"
                )
                
            else:
                # Instant Auto-Withdrawal (< 500M and < 500M hourly volume)
                tx_id = await db.create_withdrawal_request(user_id, username, val_amount, "processing")
                
                # Execute in-game transfer via bridge
                success, reason = await execute_game_transfer(tx_id, username, val_amount)
                
                if success:
                    await db.update_transaction_status(tx_id, "completed")
                    
                    user_profile = await db.get_user(user_id)
                    rem_balance = user_profile["balance"] if user_profile else 0.0

                    embed = discord.Embed(
                        title="📤 Para Çekme Başarılı",
                        description=f"🎮 **{username}** hesabınıza **{format_money_string(val_amount)}** başarıyla gönderildi!\n\nKalan Bakiyeniz: 💰 **{format_money_string(rem_balance)}**",
                        color=discord.Color.green(),
                        timestamp=datetime.utcnow()
                    )
                    embed.set_footer(text="Otomatik Anlık Çekim • KolicGamble")
                    msg = await interaction.followup.send(embed=embed, ephemeral=False)
                    
                    import asyncio
                    asyncio.create_task(schedule_message_delete(msg, 10.0))

                    await log_transaction(
                        bot=interaction.client,
                        user=interaction.user,
                        tx_type="withdraw",
                        amount=val_amount,
                        status="completed",
                        details=f"Oyun içi transfer tamamlandı. Oyun Adı: {username}"
                    )
                else:
                    # Reject and refund balance if server send failed
                    await db.update_transaction_status(tx_id, "rejected")
                    
                    if reason == "insufficient_bot_balance":
                        embed_err = discord.Embed(
                            title="🏦 Oyun İçi Bot Kasası Yetersiz!",
                            description=(
                                f"⚠️ **Çekim Gerçekleştirilemedi:**\n"
                                f"Oyun içi bot kasasında şu anda **{format_money_string(val_amount)}** tutarında nakit bulunmamaktadır.\n\n"
                                f"💰 **Bakiyeniz Güvende:** Çekmek istediğiniz tutar Discord cüzdanınıza **eksiksiz iade edilmiştir**.\n\n"
                                f"🎫 **Lütfen Destek Talebi Açınız:**\n"
                                f"Yetkililerin oyun içi bot kasasına bakiye aktarması veya paranızı manuel teslim etmesi için lütfen **`🎫・destek-talebi`** kanalından bir bilet açınız!"
                            ),
                            color=discord.Color.red(),
                            timestamp=datetime.utcnow()
                        )
                        embed_err.set_footer(text="KolicGamble Güvenli Kasa Koruması")
                        msg = await interaction.followup.send(embed=embed_err, ephemeral=False)
                        import asyncio
                        asyncio.create_task(schedule_message_delete(msg, 20.0))

                        # Alert staff in suspicious activity log
                        await log_suspicious_activity(
                            interaction.client,
                            interaction.user,
                            "INSUFFICIENT_BOT_TREASURY",
                            f"Oyuncu {username} ({interaction.user.id}) {format_money_string(val_amount)} çekmek istedi fakat oyun içi bot bakiyesi yetersiz kaldı! Kasayı doldurunuz."
                        )
                    elif reason == "player_offline":
                        embed_err = discord.Embed(
                            title="❌ Oyuncu Minecraft'ta Çevrimdışı!",
                            description=(
                                f"⚠️ **Çekim Gerçekleştirilemedi:**\n"
                                f"**`{username}`** kullanıcısı şu anda Minecraft sunucusunda aktif görünmüyor.\n\n"
                                f"Paranız Discord cüzdanınıza iade edildi. Lütfen oyuna girdikten sonra tekrar çekim yapın."
                            ),
                            color=discord.Color.orange(),
                            timestamp=datetime.utcnow()
                        )
                        msg = await interaction.followup.send(embed=embed_err, ephemeral=False)
                        import asyncio
                        asyncio.create_task(schedule_message_delete(msg, 15.0))
                    else:
                        await interaction.followup.send(f"❌ Oyun içi transfer hatası ({reason})! Çekim işlemi iptal edildi ve bakiye iade edildi.", ephemeral=True)
                        
        except InsufficientFunds:
            await interaction.followup.send("❌ Yetersiz bakiye! Lütfen çekmek istediğiniz miktarı kontrol edin.", ephemeral=True)
        except UserBanned:
            await interaction.followup.send("❌ Banlandığınız için bu işlemi gerçekleştiremezsiniz.", ephemeral=True)
        except Exception as e:
            logger.error(f"Error handling withdraw modal: {e}", exc_info=True)
            await interaction.followup.send("❌ Beklenmeyen bir hata oluştu.", ephemeral=True)

    async def send_approval_ticket(self, interaction: discord.Interaction, tx_id: int, user_id: int, username: str, amount: float, is_smurfing: bool = False, hourly_vol: float = 0.0):
        """Sends an interactive approve/reject embed to the admin panel."""
        if not config.ADMIN_APPROVAL_CHANNEL_ID:
            logger.error("ADMIN_APPROVAL_CHANNEL_ID config variable is not set!")
            return

        from utils.security import format_money_string

        embed = discord.Embed(
            title="🚨 PARÇA ÇEKİM UYARISI: Yetkili Onayı Gerekli" if is_smurfing else "⚠️ Yüksek Miktarlı Para Çekme Talebi",
            description=(
                f"⚠️ **Saatlik Hacim Aşımı:** Bu kullanıcı son 1 saatte toplam **{format_money_string(hourly_vol)}** çekim hacmine ulaştığı için işlem otomatik olarak onay kuyruğuna alındı."
                if is_smurfing else
                "Aşağıdaki para çekme talebi güvenlik sınırını aştığı için yetkili onayı bekliyor."
            ),
            color=discord.Color.red() if is_smurfing else discord.Color.orange(),
            timestamp=datetime.utcnow()
        )
        embed.add_field(name="Kullanıcı", value=f"<@{user_id}> (`{user_id}`)", inline=True)
        embed.add_field(name="Oyun İçi Adı", value=username, inline=True)
        embed.add_field(name="Talep Edilen Tutar", value=f"**{format_money_string(amount)}** ({amount:,.2f})", inline=True)
        embed.add_field(name="Talep ID", value=f"`{tx_id}`", inline=True)
        if is_smurfing:
            embed.add_field(name="Son 1 Saat Toplam Hacim", value=f"🔥 **{format_money_string(hourly_vol)}**", inline=False)
        
        # Action Buttons
        view = AdminApprovalView(tx_id=tx_id, user_id=user_id, username=username, amount=amount)
        
        await send_embed_to_channel(interaction.client, config.ADMIN_APPROVAL_CHANNEL_ID, embed)
        # Send view as well
        channel = interaction.client.get_channel(config.ADMIN_APPROVAL_CHANNEL_ID) or \
                  await interaction.client.fetch_channel(config.ADMIN_APPROVAL_CHANNEL_ID)
        if channel:
            await channel.send(view=view)


class AdminApprovalView(discord.ui.View):
    def __init__(self, tx_id: int, user_id: int, username: str, amount: float):
        super().__init__(timeout=None) # Persistent buttons
        self.tx_id = tx_id
        self.user_id = user_id
        self.username = username
        self.amount = amount

    @discord.ui.button(label="Onayla (Approve)", style=discord.ButtonStyle.success, emoji="✅", custom_id="approve_wd")
    async def approve_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
        # We check permission later, let's defer first
        await interaction.response.defer()
        
        # Verify permissions (must have Administrator or manage guild)
        if not interaction.user.guild_permissions.administrator:
            await interaction.followup.send("❌ Bu işlemi onaylamak için `Yönetici` yetkisine sahip olmalısınız.", ephemeral=True)
            return

        try:
            # Complete game transfer
            success, reason = await execute_game_transfer(self.tx_id, self.username, self.amount)
            if success:
                # Update status
                updated_tx = await db.update_transaction_status(self.tx_id, "completed", admin_id=interaction.user.id)
                
                # Edit original message to remove buttons
                embed = interaction.message.embeds[0]
                embed.title = "✅ Para Çekme Onaylandı"
                embed.color = discord.Color.green()
                embed.add_field(name="Onaylayan Yetkili", value=f"{interaction.user.mention}", inline=False)
                await interaction.message.edit(embed=embed, view=None)

                # Send log to transactions channel
                await log_transaction(
                    bot=interaction.client,
                    user=await interaction.client.fetch_user(self.user_id),
                    tx_type="withdraw_approved",
                    amount=self.amount,
                    status="completed",
                    details=f"Yetkili: {interaction.user.name}\nOyun Adı: {self.username}"
                )

                # Try to DM user
                try:
                    user = await interaction.client.fetch_user(self.user_id)
                    dm_embed = discord.Embed(
                        title="✅ Çekim Talebi Onaylandı!",
                        description=f"**{self.amount:,.2f}** tutarındaki para çekme talebiniz yetkililer tarafından onaylandı ve oyun içi hesabınıza aktarıldı.",
                        color=discord.Color.green(),
                        timestamp=datetime.utcnow()
                    )
                    await user.send(embed=dm_embed)
                except discord.Forbidden:
                    pass
            else:
                # API Call failed or bot out of money
                if reason == "insufficient_bot_balance":
                    await interaction.followup.send("❌ **Hata:** Oyun içi bot kasasında yeterli bakiye yok! Lütfen oyunda bota para aktardıktan sonra tekrar onaylayın.", ephemeral=True)
                elif reason == "player_offline":
                    await interaction.followup.send(f"❌ **Hata:** `{self.username}` şu anda oyunda çevrimdışı! Oyuncu oyuna girdiğinde tekrar onaylayın.", ephemeral=True)
                else:
                    await interaction.followup.send(f"❌ Oyun içi sisteme para gönderilirken bir hata oluştu ({reason}). Lütfen tekrar deneyin.", ephemeral=True)
        except Exception as e:
            logger.error(f"Approval error: {e}", exc_info=True)
            await interaction.followup.send("❌ İşlem sırasında beklenmedik bir hata oluştu.", ephemeral=True)

    @discord.ui.button(label="Reddet (Reject)", style=discord.ButtonStyle.danger, emoji="❌", custom_id="reject_wd")
    async def reject_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.defer()
        
        if not interaction.user.guild_permissions.administrator:
            await interaction.followup.send("❌ Bu işlemi reddetmek için `Yönetici` yetkisine sahip olmalısınız.", ephemeral=True)
            return

        try:
            # Rejecting transaction releases frozen funds back to the user
            await db.update_transaction_status(self.tx_id, "rejected", admin_id=interaction.user.id)
            
            embed = interaction.message.embeds[0]
            embed.title = "❌ Para Çekme Reddedildi"
            embed.color = discord.Color.red()
            embed.add_field(name="Reddeden Yetkili", value=f"{interaction.user.mention}", inline=False)
            await interaction.message.edit(embed=embed, view=None)

            # Send transaction log
            await log_transaction(
                bot=interaction.client,
                user=await interaction.client.fetch_user(self.user_id),
                tx_type="withdraw_rejected",
                amount=self.amount,
                status="rejected",
                details=f"Reddeden: {interaction.user.name}\nBakiye İade Edildi."
            )

            # Try to DM user
            try:
                user = await interaction.client.fetch_user(self.user_id)
                dm_embed = discord.Embed(
                    title="❌ Çekim Talebi Reddedildi",
                    description=f"**{self.amount:,.2f}** tutarındaki para çekme talebiniz yetkililer tarafından reddedildi ve bakiye hesabınıza iade edildi.",
                    color=discord.Color.red(),
                    timestamp=datetime.utcnow()
                )
                await user.send(embed=dm_embed)
            except discord.Forbidden:
                pass
        except Exception as e:
            logger.error(f"Rejection error: {e}", exc_info=True)
            await interaction.followup.send("❌ İşlem sırasında beklenmedik bir hata oluştu.", ephemeral=True)


class EconomyCog(commands.Cog, name="Ekonomi Sistemi"):
    def __init__(self, bot):
        self.bot = bot

async def setup(bot):
    await bot.add_cog(EconomyCog(bot))
