"""
Authentication helpers + permission system — Son of Anton v4.2.0
"""

from datetime import datetime, timedelta

import jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from backend.database import get_db
from backend.config import JWT_SECRET, DEFAULT_PERMISSIONS, SUPERADMIN_PERMISSIONS, PERMISSION_FIELDS

pwd_ctx = CryptContext(schemes=["bcrypt"], deprecated="auto")
bearer_scheme = HTTPBearer()


def hash_password(password: str) -> str:
    return pwd_ctx.hash(password)


def verify_password(plain: str, hashed: str) -> bool:
    return pwd_ctx.verify(plain, hashed)


def create_token(user_id: str, role: str) -> str:
    payload = {
        "sub": user_id,
        "role": role,
        "exp": datetime.utcnow() + timedelta(days=30),
    }
    return jwt.encode(payload, JWT_SECRET, algorithm="HS256")


def decode_token(token: str) -> dict:
    try:
        return jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Invalid token")


def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme),
    db: Session = Depends(get_db),
):
    from backend.models import User
    payload = decode_token(credentials.credentials)
    user = db.query(User).filter(User.id == payload["sub"]).first()
    if not user:
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "User not found")
    if not user.is_active:
        raise HTTPException(status.HTTP_403_FORBIDDEN, "Account disabled")
    return user


def require_admin(
    credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme),
    db: Session = Depends(get_db),
):
    from backend.models import User
    payload = decode_token(credentials.credentials)
    user = db.query(User).filter(User.id == payload["sub"]).first()
    if not user or user.role not in ("admin", "superadmin"):
        raise HTTPException(status.HTTP_403_FORBIDDEN, "Admin required")
    return user


def require_superadmin(
    credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme),
    db: Session = Depends(get_db),
):
    from backend.models import User
    payload = decode_token(credentials.credentials)
    user = db.query(User).filter(User.id == payload["sub"]).first()
    if not user or user.role != "superadmin":
        raise HTTPException(status.HTTP_403_FORBIDDEN, "Superadmin required")
    return user


# ═══════════════════════════════════════════════════
#  PERMISSION SYSTEM
# ═══════════════════════════════════════════════════

def get_user_permissions(user_id: str, db: Session) -> dict:
    """
    Get permissions dict for a user.
    - Superadmins always get full permissions (bypass everything).
    - Regular users get their stored permissions or defaults.
    - Auto-creates permission row if missing.
    """
    from backend.models import User, UserPermissions

    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        return dict(DEFAULT_PERMISSIONS)

    if user.role == "superadmin":
        return dict(SUPERADMIN_PERMISSIONS)

    perms = db.query(UserPermissions).filter(UserPermissions.user_id == user_id).first()
    if not perms:
        perms = _create_default_permissions(user_id, db)

    return _perms_to_dict(perms)


def get_default_permissions_template(db: Session) -> dict:
    """Get the stored default permissions template, or config defaults."""
    from backend.models import UserPermissions
    template = db.query(UserPermissions).filter(UserPermissions.user_id == "__defaults__").first()
    if template:
        return _perms_to_dict(template)
    return dict(DEFAULT_PERMISSIONS)


def ensure_user_permissions(user_id: str, db: Session):
    """Make sure a user has a permissions row. Creates one from template if missing."""
    from backend.models import UserPermissions
    existing = db.query(UserPermissions).filter(UserPermissions.user_id == user_id).first()
    if not existing:
        _create_default_permissions(user_id, db)


def _create_default_permissions(user_id: str, db: Session):
    """Create a permissions row using the stored template or config defaults."""
    from backend.models import UserPermissions
    template = get_default_permissions_template(db)
    perms = UserPermissions(user_id=user_id)
    for field in PERMISSION_FIELDS:
        if hasattr(perms, field):
            setattr(perms, field, template.get(field, DEFAULT_PERMISSIONS.get(field)))
    db.add(perms)
    db.commit()
    db.refresh(perms)
    return perms


def _perms_to_dict(perms) -> dict:
    """Convert a UserPermissions ORM object to a dict."""
    return {
        "can_use_web_search": perms.can_use_web_search,
        "can_use_ui_design": perms.can_use_ui_design,
        "can_use_knowledge_base": perms.can_use_knowledge_base,
        "can_use_gitlab": perms.can_use_gitlab,
        "can_use_attachments": perms.can_use_attachments,
        "can_export_pptx": perms.can_export_pptx,
        "can_export_docx": perms.can_export_docx,
        "allowed_models": perms.allowed_models or "all",
        "max_tokens_cap": perms.max_tokens_cap or 4096,
        "max_reasoning_budget": perms.max_reasoning_budget or 0,
        "max_chats": perms.max_chats or 0,
        "max_messages_per_day": perms.max_messages_per_day or 0,
        "max_knowledge_bases": perms.max_knowledge_bases or 0,
        "max_documents_per_kb": perms.max_documents_per_kb or 0,
        "max_attachment_size_mb": perms.max_attachment_size_mb or 10,
        "max_attachments_per_message": perms.max_attachments_per_message or 5,
    }


def check_feature(user_id: str, feature: str, db: Session):
    """Check if user has access to a feature. Raises 403 if denied."""
    perms = get_user_permissions(user_id, db)
    key = f"can_{feature}" if not feature.startswith("can_") else feature
    if not perms.get(key, False):
        raise HTTPException(
            status.HTTP_403_FORBIDDEN,
            f"Feature '{feature.replace('can_', '').replace('use_', '')}' is not enabled for your account. Contact your admin.",
        )


def check_model_allowed(user_id: str, model_id: str, db: Session) -> str:
    """Validate model access. Returns the model_id if allowed, or falls back to first allowed model."""
    perms = get_user_permissions(user_id, db)
    allowed = perms.get("allowed_models", "all")
    if allowed == "all":
        return model_id
    allowed_list = [m.strip() for m in allowed.split(",") if m.strip()]
    if model_id in allowed_list:
        return model_id
    if allowed_list:
        return allowed_list[0]
    return model_id


def count_user_messages_today(user_id: str, db: Session) -> int:
    """Count user messages sent today (UTC)."""
    from backend.models import Chat, Message
    today_start = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
    return (
        db.query(Message)
        .join(Chat)
        .filter(
            Chat.user_id == user_id,
            Message.role == "user",
            Message.created_at >= today_start,
        )
        .count()
    )


def count_user_chats(user_id: str, db: Session) -> int:
    """Count total chats for a user."""
    from backend.models import Chat
    return db.query(Chat).filter(Chat.user_id == user_id).count()


def count_user_knowledge_bases(user_id: str, db: Session) -> int:
    """Count knowledge bases owned by user."""
    from backend.models import KnowledgeBase
    return db.query(KnowledgeBase).filter(KnowledgeBase.user_id == user_id).count()


def count_kb_documents(kb_id: str, db: Session) -> int:
    """Count documents in a knowledge base."""
    from backend.models import KnowledgeDocument
    return db.query(KnowledgeDocument).filter(KnowledgeDocument.knowledge_base_id == kb_id).count()