from datetime import datetime, timedelta, timezone

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.card_key_types import CARD_TYPE_DURATION, CARD_TYPE_POINTS
from app.models.card_key import CardKey
from app.models.user import User
from app.schemas.card_key import CardKeyActivateResponse


class CardKeyActivateError(Exception):
    def __init__(self, message: str) -> None:
        self.message = message
        super().__init__(message)


def _utc_now() -> datetime:
    return datetime.now(timezone.utc)


def _ensure_utc(value: datetime) -> datetime:
    if value.tzinfo is None:
        return value.replace(tzinfo=timezone.utc)
    return value


def _extend_vip_end_time(current: datetime | None, days: int) -> datetime:
    now = _utc_now()
    if current is not None:
        end = _ensure_utc(current)
        base = end if end > now else now
    else:
        base = now
    return base + timedelta(days=days)


async def activate_card_key(
    db: AsyncSession,
    *,
    username: str,
    serial_number: str,
) -> CardKeyActivateResponse:
    user = await db.scalar(select(User).where(User.username == username))
    if user is None:
        raise CardKeyActivateError("用户不存在")

    result = await db.execute(
        select(CardKey)
        .where(CardKey.serial_number == serial_number)
        .with_for_update()
    )
    card = result.scalar_one_or_none()
    if card is None:
        raise CardKeyActivateError("卡密不存在")

    if card.activated_at is not None:
        raise CardKeyActivateError("卡密已被使用")

    now = _utc_now()
    card.activated_at = now
    card.user_id = user.id
    card.username = user.username

    if card.card_type == CARD_TYPE_DURATION:
        if card.duration_days < 1:
            raise CardKeyActivateError("卡密配置无效")
        user.vip_end_time = _extend_vip_end_time(user.vip_end_time, card.duration_days)
        await db.flush()
        await db.refresh(user)
        return CardKeyActivateResponse(
            card_type=card.card_type,
            vip_end_time=user.vip_end_time,
            points=user.points,
            added_days=card.duration_days,
        )

    if card.card_type == CARD_TYPE_POINTS:
        if card.points_amount is None or card.points_amount <= 0:
            raise CardKeyActivateError("卡密配置无效")
        user.points = (user.points or 0.0) + card.points_amount
        await db.flush()
        await db.refresh(user)
        return CardKeyActivateResponse(
            card_type=card.card_type,
            vip_end_time=user.vip_end_time,
            points=user.points,
            added_points=card.points_amount,
        )

    raise CardKeyActivateError("卡密类型无效")
