from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from models import User, UserRole
import os

SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-change-in-production")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30 * 24 * 60  # 30 days

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
security = HTTPBearer()

_db = None


def init_auth_db(database):
    """Initialize auth module with database reference for fallback lookups."""
    global _db
    _db = database

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def decode_token(token: str) -> dict:
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not validate credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
    token = credentials.credentials
    payload = decode_token(token)
    user_id: str = payload.get("sub")
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not validate credentials",
        )
    return payload

async def get_current_org(current_user: dict = Depends(get_current_user)) -> str:
    """Extract and return the organization_id from the current user's JWT.
    Falls back to a database lookup if the JWT org claim is missing.
    Raises 403 if the user has no organization assigned.
    Super admins can pass through without an org."""
    if current_user.get("role") == UserRole.SUPER_ADMIN.value:
        org_id = current_user.get("org")
        return org_id or "__super_admin__"
    org_id = current_user.get("org")
    if not org_id and _db is not None:
        user_doc = await _db.users.find_one({"id": current_user["sub"]})
        if user_doc:
            org_id = user_doc.get("organization_id")
        if not org_id:
            default_org = await _db.organizations.find_one({}, sort=[("created_at", 1)])
            if default_org:
                org_id = default_org["id"]
                await _db.users.update_one(
                    {"id": current_user["sub"]},
                    {"$set": {"organization_id": org_id}}
                )
    if not org_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="No organization assigned. Please contact your administrator.",
        )
    return org_id

def require_role(required_roles: list):
    async def role_checker(current_user: dict = Depends(get_current_user)):
        user_role = current_user.get("role")
        if user_role not in [role.value if hasattr(role, 'value') else role for role in required_roles]:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions"
            )
        return current_user
    return role_checker


async def require_super_admin(current_user: dict = Depends(get_current_user)) -> dict:
    """Dependency that ensures the current user is a super admin.
    Super admins bypass all organization boundaries."""
    if current_user.get("role") != UserRole.SUPER_ADMIN.value:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Super admin access required"
        )
    return current_user
