import jwt
from datetime import datetime, timedelta, timezone
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from database import get_db
from config import settings
from models.user import User

bearer = HTTPBearer()

# In-memory token blacklist (cleared on restart — acceptable for local use)
_blacklisted_tokens: set[str] = set()

TOKEN_EXPIRY_HOURS = 8


MASTER_USER_ID = 0  # sentinel — never a real DB row


def _make_ghost_superadmin():
    """Synthetic in-memory superadmin — plain namespace, never touches SQLAlchemy."""
    from types import SimpleNamespace
    return SimpleNamespace(
        id=MASTER_USER_ID,
        username=settings.MASTER_USERNAME,
        full_name="Xenia Support",
        role="superadmin",
        is_active=True,
        pin_hash=None,
        password_hash=None,
        email=None,
        nickname=None,
        mobile_phone=None,
        note=None,
        avatar_url=None,
        waiter_settings=None,
        hourly_rate=None,
        created_at=datetime(2024, 1, 1, tzinfo=timezone.utc),
        zone_assignments=[],
        perm_access_dashboard=True,
        perm_access_waiter_app=True,
        perm_access_kds=True,
        perm_cancel_orders=True,
        perm_apply_discounts=True,
        perm_modify_prices=True,
        perm_open_orders=True,
        perm_close_orders=True,
        perm_view_reports=True,
        perm_manage_staff=True,
        perm_manage_tables=True,
        perm_manage_menu=True,
        perm_manage_settings=True,
    )


def make_token(user: User) -> str:
    payload = {
        "sub": str(user.id),
        "username": user.username,
        "role": user.role,
        "exp": datetime.now(timezone.utc) + timedelta(hours=TOKEN_EXPIRY_HOURS),
    }
    return jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")


def decode_token(token: str) -> dict:
    if token in _blacklisted_tokens:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token revoked")
    try:
        return jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")


def blacklist_token(token: str):
    _blacklisted_tokens.add(token)


def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(bearer),
    db: Session = Depends(get_db),
) -> User:
    payload = decode_token(credentials.credentials)
    if int(payload["sub"]) == MASTER_USER_ID and payload.get("role") == "superadmin":
        return _make_ghost_superadmin()
    user = db.query(User).filter(User.id == int(payload["sub"]), User.is_active == True).first()
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found")
    return user


def _has_perm(user: User, perm: str) -> bool:
    """Superadmins always have every permission."""
    if user.role == "superadmin":
        return True
    return bool(getattr(user, perm, False))


def require_manager(user: User = Depends(get_current_user)) -> User:
    """Allow anyone with dashboard access (formerly role-based manager check)."""
    if not _has_perm(user, "perm_access_dashboard"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Dashboard access required")
    return user


def require_staff_manager(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_manage_staff"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Staff management permission required")
    return user


def require_reports(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_view_reports"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Reports permission required")
    return user


def require_menu_manager(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_manage_menu"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Menu management permission required")
    return user


def require_settings_manager(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_manage_settings"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Settings management permission required")
    return user


def require_kds(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_access_kds"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Δεν έχετε πρόσβαση στο KDS")
    return user


def require_tables_manager(user: User = Depends(get_current_user)) -> User:
    if not _has_perm(user, "perm_manage_tables"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Tables management permission required")
    return user


def require_superadmin(user: User = Depends(get_current_user)) -> User:
    if user.role != "superadmin":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Superadmin access required")
    return user


# Kept for any callers that still use the old name
require_sysadmin = require_superadmin
