from typing import Generator

from fastapi import Cookie, Depends
from sqlalchemy.orm import Session as OrmSession

from app.core.database import SessionLocal
from app.core.errors import AppError
from app.core.security import is_session_expired
from app.i18n.loader import t
from app.models.catalog import Session as SessionModel, UserAccount, ProjectRegistry, ProjectMember


def get_db() -> Generator[OrmSession, None, None]:
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


def get_current_user(
    session_token: str | None = Cookie(default=None, alias="session"),
    db: OrmSession = Depends(get_db),
) -> UserAccount:
    if not session_token:
        raise AppError(
            code="auth.not_authenticated",
            message=t("auth.not_authenticated"),
            status_code=401,
        )

    session = db.query(SessionModel).filter(SessionModel.id == session_token).first()
    if not session:
        raise AppError(
            code="auth.not_authenticated",
            message=t("auth.not_authenticated"),
            status_code=401,
        )

    if is_session_expired(session.expires_at):
        db.delete(session)
        db.commit()
        raise AppError(
            code="auth.session_expired",
            message=t("auth.session_expired"),
            status_code=401,
        )

    user = db.query(UserAccount).filter(UserAccount.id == session.user_id).first()
    if not user:
        raise AppError(
            code="user.not_found",
            message=t("user.not_found"),
            status_code=404,
        )

    if not user.is_active:
        raise AppError(
            code="user.deactivated",
            message=t("user.deactivated"),
            status_code=403,
        )

    return user


def require_admin(current_user: UserAccount = Depends(get_current_user)) -> UserAccount:
    if current_user.role != "admin":
        raise AppError(
            code="permission.admin_required",
            message=t("permission.admin_required"),
            status_code=403,
        )
    return current_user


def verify_project_access(
    project_id: str,
    db: OrmSession = Depends(get_db),
    user: UserAccount = Depends(get_current_user),
) -> str:
    """Verify the user has access to the project and return the project_id.

    Replaces the old get_project_db() dependency.
    """
    project = (
        db.query(ProjectRegistry)
        .filter(ProjectRegistry.id == project_id, ProjectRegistry.status != "deleted")
        .first()
    )
    if not project:
        raise AppError(
            code="project.not_found",
            message=t("project.not_found"),
            status_code=404,
        )

    # Check access
    if user.role != "admin":
        member = (
            db.query(ProjectMember)
            .filter(ProjectMember.project_id == project_id, ProjectMember.user_id == user.id)
            .first()
        )
        if not member:
            raise AppError(
                code="project.access_denied",
                message=t("project.access_denied"),
                status_code=403,
            )

    return project_id
