# app/crud/list.py
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import selectinload, joinedload
from sqlalchemy import or_, and_, delete as sql_delete # Use alias for delete
from typing import Optional, List as PyList # Use alias for List
from sqlalchemy import func as sql_func, desc # Import func and desc

from app.schemas.list import ListStatus # Import the new schema
from app.models import List as ListModel, UserGroup as UserGroupModel, Item as ItemModel
from app.schemas.list import ListCreate, ListUpdate

async def create_list(db: AsyncSession, list_in: ListCreate, creator_id: int) -> ListModel:
    """Creates a new list record."""
    db_list = ListModel(
        name=list_in.name,
        description=list_in.description,
        group_id=list_in.group_id,
        created_by_id=creator_id,
        is_complete=False # Default on creation
    )
    db.add(db_list)
    await db.commit()
    await db.refresh(db_list)
    return db_list

async def get_lists_for_user(db: AsyncSession, user_id: int) -> PyList[ListModel]:
    """
    Gets all lists accessible by a user:
    - Personal lists created by the user (group_id is NULL).
    - Lists belonging to groups the user is a member of.
    """
    # Get IDs of groups the user is a member of
    group_ids_result = await db.execute(
        select(UserGroupModel.group_id).where(UserGroupModel.user_id == user_id)
    )
    user_group_ids = group_ids_result.scalars().all()

    # Query for lists
    query = select(ListModel).where(
        or_(
            # Personal lists
            and_(ListModel.created_by_id == user_id, ListModel.group_id == None),
            # Group lists where user is a member
            ListModel.group_id.in_(user_group_ids)
        )
    ).order_by(ListModel.updated_at.desc()) # Order by most recently updated

    result = await db.execute(query)
    return result.scalars().all()

async def get_list_by_id(db: AsyncSession, list_id: int, load_items: bool = False) -> Optional[ListModel]:
    """Gets a single list by ID, optionally loading its items."""
    query = select(ListModel).where(ListModel.id == list_id)
    if load_items:
        # Eager load items and their creators/completers if needed
        query = query.options(
            selectinload(ListModel.items)
            .options(
                joinedload(ItemModel.added_by_user), # Use joinedload for simple FKs
                joinedload(ItemModel.completed_by_user)
            )
        )
    result = await db.execute(query)
    return result.scalars().first()

async def update_list(db: AsyncSession, list_db: ListModel, list_in: ListUpdate) -> ListModel:
    """Updates an existing list record."""
    update_data = list_in.model_dump(exclude_unset=True) # Get only provided fields
    for key, value in update_data.items():
        setattr(list_db, key, value)
    db.add(list_db) # Add to session to track changes
    await db.commit()
    await db.refresh(list_db)
    return list_db

async def delete_list(db: AsyncSession, list_db: ListModel) -> None:
    """Deletes a list record."""
    # Items should be deleted automatically due to cascade="all, delete-orphan"
    # on List.items relationship and ondelete="CASCADE" on Item.list_id FK
    await db.delete(list_db)
    await db.commit()
    return None # Or return True/False if needed

# --- Helper for Permission Checks ---
async def check_list_permission(db: AsyncSession, list_id: int, user_id: int, require_creator: bool = False) -> Optional[ListModel]:
    """
    Fetches a list and verifies user permission.

    Args:
        db: Database session.
        list_id: The ID of the list to check.
        user_id: The ID of the user requesting access.
        require_creator: If True, only allows the creator access.

    Returns:
        The ListModel if found and permission granted, otherwise None.
        (Raising exceptions might be better handled in the endpoint).
    """
    list_db = await get_list_by_id(db, list_id=list_id, load_items=True) # Load items for detail/update/delete context
    if not list_db:
        return None # List not found

    # Check if user is the creator
    is_creator = list_db.created_by_id == user_id

    if require_creator:
        return list_db if is_creator else None

    # If not requiring creator, check membership if it's a group list
    if is_creator:
        return list_db # Creator always has access

    if list_db.group_id:
        # Check if user is member of the list's group
        from app.crud.group import is_user_member # Avoid circular import at top level
        is_member = await is_user_member(db, group_id=list_db.group_id, user_id=user_id)
        return list_db if is_member else None
    else:
        # Personal list, not the creator -> no access
        return None
    
async def get_list_status(db: AsyncSession, list_id: int) -> Optional[ListStatus]:
    """
    Gets the update timestamps and item count for a list.
    Returns None if the list itself doesn't exist.
    """
    # Fetch list updated_at time
    list_query = select(ListModel.updated_at).where(ListModel.id == list_id)
    list_result = await db.execute(list_query)
    list_updated_at = list_result.scalar_one_or_none()

    if list_updated_at is None:
        return None # List not found

    # Fetch the latest item update time and count for that list
    item_status_query = (
        select(
            sql_func.max(ItemModel.updated_at).label("latest_item_updated_at"),
            sql_func.count(ItemModel.id).label("item_count")
        )
        .where(ItemModel.list_id == list_id)
    )
    item_result = await db.execute(item_status_query)
    item_status = item_result.first() # Use first() as aggregate always returns one row

    return ListStatus(
        list_updated_at=list_updated_at,
        latest_item_updated_at=item_status.latest_item_updated_at if item_status else None,
        item_count=item_status.item_count if item_status else 0
    )