# app/crud/invite.py
import secrets
from datetime import datetime, timedelta, timezone
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy import delete # Import delete statement
from typing import Optional

from app.models import Invite as InviteModel

# Invite codes should be reasonably unique, but handle potential collision
MAX_CODE_GENERATION_ATTEMPTS = 5

async def create_invite(db: AsyncSession, group_id: int, creator_id: int, expires_in_days: int = 7) -> Optional[InviteModel]:
    """Creates a new invite code for a group."""
    expires_at = datetime.now(timezone.utc) + timedelta(days=expires_in_days)
    code = None
    attempts = 0

    # Generate a unique code, retrying if a collision occurs (highly unlikely but safe)
    while attempts < MAX_CODE_GENERATION_ATTEMPTS:
        attempts += 1
        potential_code = secrets.token_urlsafe(16)
        # Check if an *active* invite with this code already exists
        existing = await db.execute(
            select(InviteModel.id).where(InviteModel.code == potential_code, InviteModel.is_active == True).limit(1)
        )
        if existing.scalar_one_or_none() is None:
            code = potential_code
            break

    if code is None:
         # Failed to generate a unique code after several attempts
         return None

    db_invite = InviteModel(
        code=code,
        group_id=group_id,
        created_by_id=creator_id,
        expires_at=expires_at,
        is_active=True
    )
    db.add(db_invite)
    await db.commit()
    await db.refresh(db_invite)
    return db_invite

async def get_active_invite_by_code(db: AsyncSession, code: str) -> Optional[InviteModel]:
    """Gets an active and non-expired invite by its code."""
    now = datetime.now(timezone.utc)
    result = await db.execute(
        select(InviteModel).where(
            InviteModel.code == code,
            InviteModel.is_active == True,
            InviteModel.expires_at > now
        )
    )
    return result.scalars().first()

async def deactivate_invite(db: AsyncSession, invite: InviteModel) -> InviteModel:
    """Marks an invite as inactive (used)."""
    invite.is_active = False
    db.add(invite) # Add to session to track change
    await db.commit()
    await db.refresh(invite)
    return invite

# Optional: Function to periodically delete old, inactive invites
# async def cleanup_old_invites(db: AsyncSession, older_than_days: int = 30): ...