from __future__ import annotations

from aiogram import Bot
from aiogram.types import User as TgUser
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import get_settings
from app.models import User


def is_admin(user_id: int) -> bool:
    return user_id in get_settings().admin_id_list


def money(value: float | int) -> str:
    """Format a balance: whole numbers without decimals, fractions with up to 2 places.
    e.g. 10 -> "10", 10.5 -> "10.5", 0.25 -> "0.25"."""
    v = round(float(value), 2)
    if v == int(v):
        return str(int(v))
    return f"{v:.2f}".rstrip("0").rstrip(".")


def parse_amount(text: str) -> float | None:
    """Parse a positive amount, accepting a comma or dot decimal (e.g. '0,1' or '0.1').
    Returns the rounded value, or None if it isn't a valid positive number."""
    value = parse_signed(text)
    if value is None or value <= 0:
        return None
    return value


def parse_signed(text: str) -> float | None:
    """Parse a signed amount ('-5', '0,5'); returns rounded float or None if invalid."""
    cleaned = (text or "").strip().replace(",", ".")
    try:
        return round(float(cleaned), 2)
    except ValueError:
        return None


async def get_or_create_user(
    session: AsyncSession, tg_user: TgUser, referrer_id: int | None = None
) -> User:
    user = await session.get(User, tg_user.id)
    if user is None:
        user = User(
            user_id=tg_user.id,
            username=tg_user.username or "",
            full_name=tg_user.full_name or "",
            referrer_id=referrer_id if referrer_id != tg_user.id else None,
        )
        session.add(user)
        if user.referrer_id:
            referrer = await session.get(User, user.referrer_id)
            if referrer:
                referrer.referred_count += 1
        await session.commit()
    else:
        # keep profile fresh
        changed = False
        if user.username != (tg_user.username or ""):
            user.username = tg_user.username or ""
            changed = True
        if user.full_name != (tg_user.full_name or ""):
            user.full_name = tg_user.full_name or ""
            changed = True
        if changed:
            await session.commit()
    return user


async def apply_topup(session: AsyncSession, topup) -> tuple[int, int, int | None] | None:
    """Credits an approved top-up: user balance + referral bonus.

    Returns (new_balance, referral_bonus, referrer_id) or None if the user is gone.
    Does NOT commit — the caller commits and sends notifications.
    """
    settings = get_settings()
    user = await session.get(User, topup.user_id)
    if user is None:
        return None
    user.balance += topup.amount
    bonus = 0.0
    referrer_id = user.referrer_id
    if referrer_id and settings.referral_percent > 0:
        referrer = await session.get(User, referrer_id)
        if referrer:
            bonus = round(topup.amount * settings.referral_percent / 100, 2)
            if bonus > 0:
                referrer.balance += bonus
                referrer.referral_earned += bonus
    return user.balance, bonus, referrer_id


async def notify_admins(bot: Bot, text: str, reply_markup=None) -> None:
    for admin_id in get_settings().admin_id_list:
        try:
            await bot.send_message(admin_id, text, reply_markup=reply_markup)
        except Exception:
            continue
