import logging
import discord
from discord.ext import commands
from utils.bank_functions import *
from discord.ext import commands
from datetime import datetime, timedelta
from random import randint
from typing import Literal
import datetime


async def check_transfer(
    ctx: commands.Context,
    payer_balance: int,
    receiver_balance: int,
    member: discord.Member,
    amount: int,
) -> bool:
    """Check if a transfer is valid.

    Args:
    - ctx (commands.Context): The context of the invoked command.
    - payer_balance (int): The balance of the payer.
    - receiver_balance (int): The balance of the receiver.
    - member (discord.Member): The member to check against.
    - amount (int): The amount to transfer.

    Returns:
    - bool: Whether the transfer is valid.
    """
    if payer_balance is None or receiver_balance is None:
        await ctx.reply("Bank account doesn't exist.")
        return False
    if payer_balance >= amount > 0:
        payer_balance = payer_balance - amount
        receiver_balance = receiver_balance + amount
        if ctx.author.id != member.id:
            return True
        else:
            await ctx.reply("You cannot give yourself money.")
            return False
    else:
        await ctx.reply(
            f"You do not have {int(amount):,}<:flooney:1194943899765051473>.\nYou have {int(payer_balance):,}<:flooney:1194943899765051473>."
        )
        return False


class Economy(commands.Cog):
    def __init__(self, client):
        self.client = client
        self.db = DatabaseManager("")

    r"""  
    .----------------.  .----------------.  .----------------.  .----------------.  .-----------------.
    | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. |
    | |      __      | || |  ________    | || | ____    ____ | || |     _____    | || | ____  _____  | |
    | |     /  \     | || | |_   ___ `.  | || ||_   \  /   _|| || |    |_   _|   | || ||_   \|_   _| | |
    | |    / /\ \    | || |   | |   `. \ | || |  |   \/   |  | || |      | |     | || |  |   \ | |   | |
    | |   / ____ \   | || |   | |    | | | || |  | |\  /| |  | || |      | |     | || |  | |\ \| |   | |
    | | _/ /    \ \_ | || |  _| |___.' / | || | _| |_\/_| |_ | || |     _| |_    | || | _| |_\   |_  | |
    | ||____|  |____|| || | |________.'  | || ||_____||_____|| || |    |_____|   | || ||_____|\____| | |
    | |              | || |              | || |              | || |              | || |              | |
    | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' |
    '----------------'  '----------------'  '----------------'  '----------------'  '----------------' 
    """

    @commands.command(
        name="give_money",
        aliases=["addmoney"],
        usage="<member*: @member> <amount*: integer>",
    )
    @commands.is_owner()
    @commands.cooldown(3, 2 * 60, commands.BucketType.user)
    async def add_money(
        self, ctx: commands.Context, member: discord.Member, amount_str: str
    ):
        """Add money to a user's bank."""
        if member.bot:
            return await ctx.reply("You can't add money to a bot", mention_author=False)
        if not member:
            member = ctx.author

        try:
            amount = int(amount_str)
        except ValueError:
            return await ctx.reply("Please enter a valid amount")

        if amount <= 0:
            return await ctx.reply("Please enter an amount greater than 0")

        limit = 1_000_000
        if amount > limit:
            return await ctx.reply(f"You cannot add money more than {limit:,}")

        await update_money(member, amount)
        await ctx.reply(
            f"You added {amount:,} in {member.mention}'s bank.", mention_author=False
        )

    @commands.command(
        aliases=["remoney"],
        usage="<member*: @member> <amount*: integer> <mode: wallet or bank>",
    )
    @commands.is_owner()
    @commands.cooldown(3, 2 * 60, commands.BucketType.user)
    async def remove_money(
        self, ctx, member: discord.Member, amount_str: str, mode: str = "bank"
    ):
        mode = mode.lower()
        if member.bot:
            return await ctx.reply(
                "You can't remove money from a bot", mention_author=False
            )

        try:
            amount = int(amount_str)
            if amount <= 0:
                raise ValueError
        except ValueError:
            return await ctx.reply("Please enter a valid amount")

        if mode not in ["wallet", "bank"]:
            return await ctx.reply("Please enter either wallet or bank only")

        user_balance = await bank_data(member)
        current_balance = user_balance["BANK" if mode == "bank" else "WALLET"]

        if current_balance < amount:
            return await ctx.reply(
                f"You can only remove {current_balance:,} from {member.mention}'s {mode}"
            )

        if mode == "bank":
            await update_money(member, bank=-amount)
        else:
            await update_money(member, wallet=-amount)

        await ctx.reply(
            f"You removed {amount:,} from {member.mention}'s {mode}",
            mention_author=False,
        )

    @commands.command(usage="<member*: @member>")
    @commands.is_owner()
    @commands.cooldown(2, 3 * 60, commands.BucketType.user)
    async def reset_money(self, ctx, member: discord.Member):
        if member.bot:
            return await ctx.reply(
                "Bots don't have bank accounts", mention_author=False
            )

        await reset_bank(member)

        return await ctx.reply(
            f"{member.mention}'s account has been reset", mention_author=False
        )

    r"""
    .----------------.  .----------------.  .-----------------. .----------------. 
    | .--------------. || .--------------. || .--------------. || .--------------. |
    | |   ______     | || |      __      | || | ____  _____  | || |  ___  ____   | |
    | |  |_   _ \    | || |     /  \     | || ||_   \|_   _| | || | |_  ||_  _|  | |
    | |    | |_) |   | || |    / /\ \    | || |  |   \ | |   | || |   | |_/ /    | |
    | |    |  __'.   | || |   / ____ \   | || |  | |\ \| |   | || |   |  __'.    | |
    | |   _| |__) |  | || | _/ /    \ \_ | || | _| |_\   |_  | || |  _| |  \ \_  | |
    | |  |_______/   | || ||____|  |____|| || ||_____|\____| | || | |____||____| | |
    | |              | || |              | || |              | || |              | |
    | '--------------' || '--------------' || '--------------' || '--------------' |
    '----------------'  '----------------'  '----------------'  '----------------' 
    """

    @commands.command(
        name="balance",
        aliases=["bal"],
        brief="Check your money",
        description="Check how much money you have.",
    )
    async def _balance(
        self, ctx: commands.Context, member: discord.Member | None = None
    ):
        """
        Check how much money you have.
        """
        target: discord.Member | discord.User = member or ctx.author

        # Ensure the target is not a bot
        if target.bot:
            return

        # Get the user's data
        user_data = await bank_data(target)
        wallet_balance = user_data.get("WALLET", 0)
        bank_balance = user_data.get("BANK", 0)

        # Create an account if one does not exist
        if bank_balance is None or wallet_balance is None:
            await create_account(target)
            user_data = await bank_data(target)
            wallet_balance = user_data.get("WALLET", 0)
            bank_balance = user_data.get("BANK", 0)

        # Reply with the user's balance
        await ctx.reply(
            f"{target.mention} has {bank_balance:,}<:flooney:1194943899765051473> in their bank and "
            f"{wallet_balance:,}<:flooney:1194943899765051473> in their wallet."
        )

    @commands.command(name="give")
    async def _give(self, ctx, target: discord.Member, amount: int):
        """Give money to another user."""

        payer_wallet = int((await bank_data(ctx.author)).get("WALLET", 0))
        receiver_wallet = int((await bank_data(target)).get("WALLET", 0))

        if await check_transfer(ctx, payer_wallet, receiver_wallet, target, amount):
            await update_money(target, wallet=amount)
            await update_money(ctx.author, wallet=-amount)

            await ctx.reply(
                f"You gave {target} {amount:,} flooneys.", mention_author=False
            )

    @commands.command(name="transfer")
    async def _transfer(self, ctx, target: discord.Member, amount: int):
        """
        Transfer money from your bank account to another user's bank account.
        """
        payer_bank = int((await bank_data(ctx.author)).get("BANK", 0))
        receiver_bank = int((await bank_data(target)).get("BANK", 0))

        if await check_transfer(ctx, payer_bank, receiver_bank, target, amount):
            await update_money(target, bank=amount)
            await update_money(ctx.author, bank=-amount)

            await ctx.reply(
                f"Transferred {amount:,} flooneys to {target}.", mention_author=False
            )

    @commands.command(
        name="deposit",
        aliases=["dep"],
        brief="Deposit money",
        description="Deposit money from your wallet to the bank",
    )
    async def _deposit(self, ctx, amount: int | Literal["all"] = 0) -> None:
        """Deposit money from your wallet to your bank account. Amount can be an integer or 'all' to deposit all money from wallet."""

        user_data = await bank_data(ctx.author)
        if user_data is None:
            await create_account(ctx)
            user_data = await bank_data(ctx.author)

        wallet_balance = int(user_data.get("WALLET", 0))

        if amount == "all":
            amount = wallet_balance

        if 0 <= amount <= wallet_balance:
            await update_money(ctx.author, bank=amount, wallet=-amount)
            await ctx.reply("Transaction successful.")
        else:
            await ctx.reply("Insufficient funds in wallet")

    @commands.command(name="withdraw", brief="Withdraw money from bank to wallet")
    async def _withdraw(self, ctx, amount: int | Literal["all"] = 0) -> None:
        """Withdraw money from your bank account to your wallet. Amount can be an integer or 'all' to withdraw all money from bank."""

        user_data = await bank_data(ctx.author)
        if user_data is None:
            await create_account(ctx)
            user_data = await bank_data(ctx.author)

        bank_balance = int(user_data.get("BANK", 0))

        if amount == "all":
            amount = bank_balance

        if 0 <= amount <= bank_balance:
            await update_money(ctx.author, bank=-amount, wallet=amount)
            await ctx.reply("Transaction successful.")
        else:
            await ctx.reply("Insufficient funds")

    @commands.command(aliases=["lb"])
    @commands.guild_only()
    async def leaderboard(self, ctx):
        users_data = self.db.fetch_all(
            "SELECT * FROM economy ORDER BY BANK + WALLET DESC"
        )

        leaderboard_entries = []
        position = 1
        for user_data in users_data:
            user_id = int(user_data["ID"])
            user = ctx.guild.get_member(user_id) or self.client.get_user(user_id)
            if user is None:
                try:
                    user = await self.client.fetch_user(user_id)
                    user_display = (
                        user.display_name
                        if hasattr(user, "display_name")
                        else str(user)
                    )
                except Exception:
                    user_display = f"User {user_id}"
            else:
                user_display = (
                    user.display_name if hasattr(user, "display_name") else str(user)
                )

            total_balance = int(user_data["BANK"]) + int(user_data["WALLET"])
            flooney_icon = "<:flooney:1194943899765051473>"

            if position <= 3:
                entry = f"{['🥇', '🥈', '🥉'][position-1]}**{position} {user_display}** -- {total_balance:,}{flooney_icon} "
            else:
                entry = (
                    f"**{position} {user_display}** -- {total_balance:,}{flooney_icon}"
                )

            leaderboard_entries.append(entry)
            position += 1
            if position > 10:
                break

        embed = discord.Embed(
            title=f"Top {len(leaderboard_entries)} Richest Users - Leaderboard",
            description="\n".join(leaderboard_entries),
            color=discord.Color(0x00FF00),
            timestamp=datetime.datetime.utcnow(),
        )
        embed.set_footer(text=f"GLOBAL - {ctx.guild.name}")
        await ctx.reply(embed=embed, mention_author=False)

    r"""
    .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------.  .----------------. 
    | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. |
    | |   ______     | || |  _________   | || |  _______     | || |     _____    | || |     ____     | || |  ________    | || |     _____    | || |     ______   | || |      __      | || |   _____      | || |   _____      | || |  ____  ____  | |
    | |  |_   __ \   | || | |_   ___  |  | || | |_   __ \    | || |    |_   _|   | || |   .'    `.   | || | |_   ___ `.  | || |    |_   _|   | || |   .' ___  |  | || |     /  \     | || |  |_   _|     | || |  |_   _|     | || | |_  _||_  _| | |
    | |    | |__) |  | || |   | |_  \_|  | || |   | |__) |   | || |      | |     | || |  /  .--.  \  | || |   | |   `. \ | || |      | |     | || |  / .'   \_|  | || |    / /\ \    | || |    | |       | || |    | |       | || |   \ \  / /   | |
    | |    |  ___/   | || |   |  _|  _   | || |   |  __ /    | || |      | |     | || |  | |    | |  | || |   | |    | | | || |      | |     | || |  | |         | || |   / ____ \   | || |    | |   _   | || |    | |   _   | || |    \ \/ /    | |
    | |   _| |_      | || |  _| |___/ |  | || |  _| |  \ \_  | || |     _| |_    | || |  \  `--'  /  | || |  _| |___.' / | || |     _| |_    | || |  \ `.___.'\  | || | _/ /    \ \_ | || |   _| |__/ |  | || |   _| |__/ |  | || |    _|  |_    | |
    | |  |_____|     | || | |_________|  | || | |____| |___| | || |    |_____|   | || |   `.____.'   | || | |________.'  | || |    |_____|   | || |   `._____.'  | || ||____|  |____|| || |  |________|  | || |  |________|  | || |   |______|   | |
    | |              | || |              | || |              | || |              | || |              | || |              | || |              | || |              | || |              | || |              | || |              | || |              | |
    | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' |
    '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------'  '----------------' 
    """

    @commands.command(name="daily", help="Claim your daily pocket money")
    async def claim_daily_money(self, ctx: commands.Context) -> None:
        """Claim your daily pocket money. You can claim once every 24 hours."""
        try:
            user_data = await bank_data(ctx.author)
            last_claim = user_data.get("DAILY")
            now = discord.utils.utcnow()  # Modern, timezone-aware

            # Convert last_claim to datetime if it's a timestamp (int or float)
            if last_claim:
                if isinstance(last_claim, (int, float)):
                    last_claim_dt = datetime.datetime.fromtimestamp(
                        last_claim, tz=datetime.timezone.utc
                    )
                elif isinstance(last_claim, str):
                    try:
                        last_claim_dt = datetime.datetime.fromtimestamp(
                            float(last_claim), tz=datetime.timezone.utc
                        )
                    except Exception:
                        last_claim_dt = None
                elif isinstance(last_claim, datetime.datetime):
                    # If it's naive, make it aware
                    if last_claim.tzinfo is None:
                        last_claim_dt = last_claim.replace(tzinfo=datetime.timezone.utc)
                    else:
                        last_claim_dt = last_claim
                else:
                    last_claim_dt = None
            else:
                last_claim_dt = None

            if not last_claim_dt or (now - last_claim_dt).total_seconds() >= 86400:
                daily_reward = randint(200, 1000)
                await update_money(ctx.author, daily_reward)
                # Save the new timestamp as a float (UNIX time)
                await update_daily_timestamp(ctx.author, now)
                await ctx.reply(
                    f"Your daily pocket money is {daily_reward:,}<:flooney:1194943899765051473>",
                    mention_author=False,
                )
            else:
                next_claim = last_claim_dt + timedelta(days=1)
                time_left = next_claim - now
                hours, remainder = divmod(int(time_left.total_seconds()), 3600)
                minutes, seconds = divmod(remainder, 60)
                await ctx.reply(
                    f"Already claimed today. You need to wait **{hours}H {minutes}M {seconds}S**.",
                    mention_author=False,
                )
        except Exception as e:
            logging.error(f"Error in daily claim: {e}")
            await ctx.reply(
                f"An error occurred while claiming your daily reward. {e}",
                mention_author=False,
            )

    r"""
    .----------------.  .----------------.  .----------------.  .----------------. 
    | .--------------. || .--------------. || .--------------. || .--------------. |
    | |     _____    | || |     ____     | || |   ______     | || |    _______   | |
    | |    |_   _|   | || |   .'    `.   | || |  |_   _ \    | || |   /  ___  |  | |
    | |      | |     | || |  /  .--.  \  | || |    | |_) |   | || |  |  (__ \_|  | |
    | |   _  | |     | || |  | |    | |  | || |    |  __'.   | || |   '.___`-.   | |
    | |  | |_' |     | || |  \  `--'  /  | || |   _| |__) |  | || |  |`\____) |  | |
    | |  `.___.'     | || |   `.____.'   | || |  |_______/   | || |  |_______.'  | |
    | |              | || |              | || |              | || |              | |
    | '--------------' || '--------------' || '--------------' || '--------------' |
    '----------------'  '----------------'  '----------------'  '----------------' 
    """


async def setup(client):
    await client.add_cog(Economy(client))
