from typing import Annotated, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_

from app.core.database import get_db
from app.models.step_category import StepCategory
from app.models.user import User
from app.schemas.step_category import (
    StepCategoryCreate,
    StepCategoryUpdate,
    StepCategoryResponse,
    StepCategoryListResponse,
    slugify
)
from app.api.deps import get_current_active_user
from app.core.permissions import can_manage_step_category, can_create_step_category

router = APIRouter(prefix="/step-categories", tags=["step-categories"])


@router.get("", response_model=list[StepCategoryListResponse])
async def list_step_categories(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)],
    include_inactive: bool = Query(False, description="Include inactive categories"),
    account_only: bool = Query(False, description="Only show account-specific categories")
):
    """List step categories visible to the user.

    Returns global categories plus account-specific categories for the user's account.
    """
    # Build query for accessible categories
    query = select(StepCategory)

    # Filter by active status
    if not include_inactive:
        query = query.where(StepCategory.is_active == True)

    # Filter by visibility: global OR user's account
    if account_only and current_user.account_id:
        query = query.where(StepCategory.account_id == current_user.account_id)
    elif current_user.account_id:
        query = query.where(
            or_(
                StepCategory.account_id.is_(None),  # Global
                StepCategory.account_id == current_user.account_id  # User's account
            )
        )
    else:
        # User has no account, only show global categories
        query = query.where(StepCategory.account_id.is_(None))

    query = query.order_by(StepCategory.display_order, StepCategory.name)

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

    # For now, step_count will be 0 since step_library table doesn't exist yet
    # This will be updated in Issue #7 when we have the step_library table
    response = []
    for cat in categories:
        response.append(StepCategoryListResponse(
            id=cat.id,
            name=cat.name,
            slug=cat.slug,
            description=cat.description,
            account_id=cat.account_id,
            display_order=cat.display_order,
            is_active=cat.is_active,
            step_count=0  # Will be computed when step_library exists
        ))

    return response


@router.get("/{category_id}", response_model=StepCategoryResponse)
async def get_step_category(
    category_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)]
):
    """Get a specific step category by ID."""
    result = await db.execute(select(StepCategory).where(StepCategory.id == category_id))
    category = result.scalar_one_or_none()

    if not category:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Step category not found"
        )

    # Check access: global categories visible to all, account categories only to account members
    if category.account_id and category.account_id != current_user.account_id and not current_user.is_super_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You don't have access to this step category"
        )

    return StepCategoryResponse(
        id=category.id,
        name=category.name,
        slug=category.slug,
        description=category.description,
        account_id=category.account_id,
        display_order=category.display_order,
        is_active=category.is_active,
        created_at=category.created_at,
        updated_at=category.updated_at,
        step_count=0  # Will be computed when step_library exists
    )


@router.post("", response_model=StepCategoryResponse, status_code=status.HTTP_201_CREATED)
async def create_step_category(
    category_data: StepCategoryCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)]
):
    """Create a new step category.

    - Global admins can create global categories (account_id=None)
    - Account admins can create account-specific categories for their account
    """
    if not can_create_step_category(current_user, category_data.account_id):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You don't have permission to create this step category"
        )

    # Generate slug
    slug = slugify(category_data.name)

    # Check for duplicate slug within same scope (global or account)
    existing_query = select(StepCategory).where(
        StepCategory.slug == slug,
        StepCategory.account_id == category_data.account_id
    )
    existing = await db.execute(existing_query)
    if existing.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"A step category with slug '{slug}' already exists"
        )

    # Get next display order
    order_query = select(func.max(StepCategory.display_order)).where(
        StepCategory.account_id == category_data.account_id
    )
    order_result = await db.execute(order_query)
    max_order = order_result.scalar() or 0

    new_category = StepCategory(
        name=category_data.name,
        slug=slug,
        description=category_data.description,
        account_id=category_data.account_id,
        display_order=max_order + 1,
        created_by=current_user.id
    )
    db.add(new_category)
    await db.commit()
    await db.refresh(new_category)

    return StepCategoryResponse(
        id=new_category.id,
        name=new_category.name,
        slug=new_category.slug,
        description=new_category.description,
        account_id=new_category.account_id,
        display_order=new_category.display_order,
        is_active=new_category.is_active,
        created_at=new_category.created_at,
        updated_at=new_category.updated_at,
        step_count=0
    )


@router.put("/{category_id}", response_model=StepCategoryResponse)
async def update_step_category(
    category_id: UUID,
    category_data: StepCategoryUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)]
):
    """Update a step category."""
    result = await db.execute(select(StepCategory).where(StepCategory.id == category_id))
    category = result.scalar_one_or_none()

    if not category:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Step category not found"
        )

    if not can_manage_step_category(current_user, category):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You don't have permission to update this step category"
        )

    # Update fields
    update_data = category_data.model_dump(exclude_unset=True)

    # If name is being updated, regenerate slug
    if "name" in update_data:
        new_slug = slugify(update_data["name"])
        # Check for duplicate slug
        existing_query = select(StepCategory).where(
            StepCategory.slug == new_slug,
            StepCategory.account_id == category.account_id,
            StepCategory.id != category_id
        )
        existing = await db.execute(existing_query)
        if existing.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"A step category with slug '{new_slug}' already exists"
            )
        category.slug = new_slug

    for field, value in update_data.items():
        setattr(category, field, value)

    await db.commit()
    await db.refresh(category)

    return StepCategoryResponse(
        id=category.id,
        name=category.name,
        slug=category.slug,
        description=category.description,
        account_id=category.account_id,
        display_order=category.display_order,
        is_active=category.is_active,
        created_at=category.created_at,
        updated_at=category.updated_at,
        step_count=0  # Will be computed when step_library exists
    )


@router.delete("/{category_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_step_category(
    category_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)]
):
    """Soft delete (archive) a step category."""
    result = await db.execute(select(StepCategory).where(StepCategory.id == category_id))
    category = result.scalar_one_or_none()

    if not category:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Step category not found"
        )

    if not can_manage_step_category(current_user, category):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You don't have permission to delete this step category"
        )

    category.is_active = False
    await db.commit()
    return None
