"""User authentication."""
import bcrypt
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from fastapi import HTTPException, status, Depends
from fastapi.security import OAuth2PasswordBearer
from api.constants import Role
import os

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


def hash_password(password: str) -> str:
    """Hash password using bcrypt."""
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """Verify password against hash."""
    return bcrypt.checkpw(plain_password.encode(), hashed_password.encode())


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """Create JWT access token."""
    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 verify_token(token: str) -> Optional[dict]:
    """Verify JWT token and return payload."""
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        return None


def create_user(db, email: str, password: str, name: Optional[str] = None):
    """Create a new user (db parameter kept for compatibility but uses Firestore)."""
    from api.firestore_db import get_user_by_email, create_user as fs_create_user
    
    # Check if user exists
    existing = get_user_by_email(email)
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="User with this email already exists"
        )
    
    user_data = {
        'email': email,
        'password_hash': hash_password(password),
        'name': name,
        'email_verified': False,
        'subscription_plan': None,
        'subscription_status': 'inactive'
    }
    user = fs_create_user(user_data)
    return user


def authenticate_user(db, email: str, password: str):
    """Authenticate user and return user if valid (db parameter kept for compatibility)."""
    from api.firestore_db import get_user_by_email
    
    user = get_user_by_email(email)
    if not user:
        return None
    if not verify_password(password, user.get('password_hash', '')):
        return None
    return user


def get_user_organizations(db, user_id: str):
    """Get all organizations a user belongs to (db parameter kept for compatibility)."""
    from api.firestore_db import get_organization, db as fs_db, COLLECTIONS
    
    if not fs_db:
        return []
    
    # Query org_members by user_id
    memberships = fs_db.collection(COLLECTIONS['org_members']).where('user_id', '==', user_id).stream()
    orgs = []
    for membership_doc in memberships:
        membership = membership_doc.to_dict()
        if not membership:
            continue
        membership['id'] = membership_doc.id  # Ensure ID is included
        org = get_organization(membership.get('organization_id'))
        if org:
            orgs.append({
                "id": org['id'],
                "name": org['name'],
                "role": membership.get('role', 'engineer'),
                "plan": org.get('plan', 'free')
            })
    return orgs


def get_user_id(current_user) -> str:
    """Helper to get user ID from current_user (handles both dict and object)."""
    if isinstance(current_user, dict):
        return current_user.get('id')
    return current_user.id


def check_org_access(db, user_id: str, organization_id: str, min_role: Role = Role.ENGINEER) -> bool:
    """Check if user has access to organization with at least min_role."""
    from api.firestore_db import get_org_member
    
    # Use Firestore
    member = get_org_member(user_id, organization_id)
    if not member:
        return False
    
    # Role hierarchy: OWNER > ADMIN > ENGINEER > AUDITOR
    role_hierarchy = {
        'owner': 4,
        'admin': 3,
        'engineer': 2,
        'auditor': 1
    }
    
    user_role = member.get('role', 'engineer')
    if isinstance(user_role, str):
        user_level = role_hierarchy.get(user_role.lower(), 0)
    else:
        # Handle enum
        user_level = role_hierarchy.get(user_role.value.lower() if hasattr(user_role, 'value') else str(user_role).lower(), 0)
    
    required_level = role_hierarchy.get(min_role.value.lower() if hasattr(min_role, 'value') else str(min_role).lower(), 0)
    return user_level >= required_level


def check_read_access(db, user_id: str, organization_id: str) -> bool:
    """Check if user has read access (any role)."""
    return check_org_access(db, user_id, organization_id, Role.AUDITOR)


# OAuth2 scheme for token extraction
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")


def get_current_user(
    token: str = Depends(oauth2_scheme)
):
    """Get current user from JWT token or Firebase token."""
    # Try Firebase token first
    try:
        from api.firebase_auth import get_user_from_firebase_token
        user = get_user_from_firebase_token(token, None)  # db parameter not needed with Firestore
        if user:
            return user
    except Exception as e:
        # Firebase auth not configured or failed, fall through to JWT
        pass
    
    # Fallback to JWT token (for backward compatibility)
    payload = verify_token(token)
    if not payload:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )
    user_id = payload.get("sub")
    if not user_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token"
        )
    from api.firestore_db import get_user
    user = get_user(user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found"
        )
    return user

