"""
Custom Decorators
=================

Reusable decorators for access control and validation.

Role-based decorators (new system):
- @role_required(SystemRole.OFFICE_MANAGER) - Minimum role check
- @company_permission('edit') - Company-specific permissions
- @member_required - Shortcut for role >= MEMBER

Legacy decorators (backward compatibility):
- @admin_required - Alias for @role_required(SystemRole.ADMIN)
- @company_owner_or_admin - Uses new can_edit_company() method
"""

from functools import wraps
from flask import abort, flash, redirect, url_for, request
from flask_login import current_user

# Audit access restriction — only this user sees SEO/IT/GBP/Social audits
AUDIT_OWNER_EMAIL = 'maciej.pienczyn@inpi.pl'

def is_audit_owner():
    """True only for the designated audit owner."""
    if not current_user.is_authenticated:
        return False
    return current_user.email == AUDIT_OWNER_EMAIL

# Import role enums (lazy import to avoid circular dependencies)
def _get_system_role():
    from database import SystemRole
    return SystemRole


# ============================================================
# NEW ROLE-BASED DECORATORS
# ============================================================

def role_required(min_role):
    """
    Decorator that requires user to have at least the specified role.

    Args:
        min_role: Minimum SystemRole required (e.g., SystemRole.OFFICE_MANAGER)

    Usage:
        @bp.route('/admin/companies')
        @login_required
        @role_required(SystemRole.OFFICE_MANAGER)
        def admin_companies():
            ...

    Note: Always use @login_required BEFORE @role_required
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.is_authenticated:
                return redirect(url_for('auth.login'))

            if not current_user.has_role(min_role):
                SystemRole = _get_system_role()
                role_names = {
                    SystemRole.MEMBER: 'członka Izby',
                    SystemRole.EMPLOYEE: 'pracownika firmy',
                    SystemRole.MANAGER: 'kadry zarządzającej',
                    SystemRole.OFFICE_MANAGER: 'kierownika biura',
                    SystemRole.ADMIN: 'administratora',
                }
                role_name = role_names.get(min_role, 'wyższych uprawnień')
                flash(f'Ta strona wymaga uprawnień {role_name}.', 'error')
                return redirect(url_for('public.index'))

            return f(*args, **kwargs)
        return decorated_function
    return decorator


def member_required(f):
    """
    Decorator that requires user to be at least a MEMBER.
    Shortcut for @role_required(SystemRole.MEMBER).

    Usage:
        @bp.route('/forum')
        @login_required
        @member_required
        def forum_index():
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        SystemRole = _get_system_role()
        if not current_user.has_role(SystemRole.MEMBER):
            flash('Ta strona jest dostępna tylko dla członków Izby NORDA.', 'warning')
            return redirect(url_for('public.index'))

        return f(*args, **kwargs)
    return decorated_function


def company_permission(permission_type='edit'):
    """
    Decorator that checks user's permission for a company.

    Args:
        permission_type: 'view', 'edit', or 'manage'

    The company_id is extracted from:
    1. URL parameter 'company_id'
    2. Query parameter 'company_id'
    3. User's own company_id

    Usage:
        @bp.route('/company/<int:company_id>/edit')
        @login_required
        @company_permission('edit')
        def edit_company(company_id):
            ...

        @bp.route('/company/<int:company_id>/users')
        @login_required
        @company_permission('manage')
        def manage_company_users(company_id):
            ...
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.is_authenticated:
                return redirect(url_for('auth.login'))

            # Get company_id from various sources
            company_id = (
                kwargs.get('company_id') or
                request.args.get('company_id', type=int) or
                current_user.company_id
            )

            if company_id is None:
                flash('Nie określono firmy.', 'error')
                return redirect(url_for('public.index'))

            # Check permission based on type
            has_permission = False
            if permission_type == 'view':
                # Anyone can view public companies, but for dashboard check company membership
                has_permission = (
                    current_user.can_access_admin_panel() or
                    current_user.company_id == company_id
                )
            elif permission_type == 'edit':
                has_permission = current_user.can_edit_company(company_id)
            elif permission_type == 'manage':
                has_permission = current_user.can_manage_company(company_id)
            else:
                abort(500, f"Unknown permission type: {permission_type}")

            if not has_permission:
                flash('Nie masz uprawnień do tej operacji.', 'error')
                return redirect(url_for('public.index'))

            return f(*args, **kwargs)
        return decorated_function
    return decorator


def office_manager_required(f):
    """
    Decorator that requires user to be at least OFFICE_MANAGER.
    Shortcut for @role_required(SystemRole.OFFICE_MANAGER).

    Usage:
        @bp.route('/admin/companies')
        @login_required
        @office_manager_required
        def admin_companies():
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        SystemRole = _get_system_role()
        if not current_user.has_role(SystemRole.OFFICE_MANAGER):
            flash('Ta strona wymaga uprawnień kierownika biura.', 'error')
            return redirect(url_for('public.index'))

        return f(*args, **kwargs)
    return decorated_function


def forum_access_required(f):
    """
    Decorator that requires user to have forum access.
    Members and above can access the forum.

    Usage:
        @bp.route('/forum/topic/<int:topic_id>')
        @login_required
        @forum_access_required
        def view_topic(topic_id):
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        if not current_user.can_access_forum():
            flash('Forum jest dostępne tylko dla członków Izby NORDA.', 'warning')
            return redirect(url_for('public.index'))

        return f(*args, **kwargs)
    return decorated_function


def moderator_required(f):
    """
    Decorator that requires forum moderator permissions.
    OFFICE_MANAGER and ADMIN roles have this permission.

    Usage:
        @bp.route('/forum/topic/<int:topic_id>/delete')
        @login_required
        @moderator_required
        def delete_topic(topic_id):
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        if not current_user.can_moderate_forum():
            flash('Ta akcja wymaga uprawnień moderatora.', 'error')
            return redirect(url_for('public.index'))

        return f(*args, **kwargs)
    return decorated_function


def rada_member_required(f):
    """
    Decorator that requires user to be a member of Rada Izby (Board Council).
    OFFICE_MANAGER and ADMIN roles also have access for management purposes.

    Usage:
        @bp.route('/rada/')
        @login_required
        @rada_member_required
        def board_index():
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        SystemRole = _get_system_role()
        # Allow access if: is_rada_member OR has OFFICE_MANAGER/ADMIN role
        if not current_user.is_rada_member and not current_user.has_role(SystemRole.OFFICE_MANAGER):
            flash('Strefa RADA jest dostępna tylko dla członków Rady Izby.', 'warning')
            return redirect(url_for('public.index'))

        return f(*args, **kwargs)
    return decorated_function


# ============================================================
# LEGACY DECORATORS (backward compatibility)
# ============================================================

def admin_required(f):
    """
    Decorator that requires user to be logged in AND be an admin.

    DEPRECATED: Use @role_required(SystemRole.ADMIN) instead.

    Usage:
        @bp.route('/admin/users')
        @login_required
        @admin_required
        def admin_users():
            ...

    Note: Always use @login_required BEFORE @admin_required
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        # Use role system (is_admin fallback removed — role is source of truth)
        SystemRole = _get_system_role()
        if not current_user.has_role(SystemRole.ADMIN):
            flash('Brak uprawnień administratora.', 'error')
            return redirect(url_for('public.index'))
        return f(*args, **kwargs)
    return decorated_function


def verified_required(f):
    """
    Decorator that requires user to have verified email.

    Usage:
        @bp.route('/forum/new')
        @login_required
        @verified_required
        def new_topic():
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))
        if not current_user.is_verified:
            flash('Musisz zweryfikować swój email, aby wykonać tę akcję.', 'warning')
            return redirect(url_for('auth.resend_verification'))
        return f(*args, **kwargs)
    return decorated_function


def company_owner_or_admin(f):
    """
    Decorator for routes that accept company_id.
    Allows access only if user is admin OR owns the company.

    DEPRECATED: Use @company_permission('edit') instead.

    Usage:
        @bp.route('/company/<int:company_id>/edit')
        @login_required
        @company_owner_or_admin
        def edit_company(company_id):
            ...
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('auth.login'))

        company_id = kwargs.get('company_id')
        if company_id is None:
            abort(400)

        # Use new permission system
        if current_user.can_edit_company(company_id):
            return f(*args, **kwargs)

        flash('Nie masz uprawnień do tej firmy.', 'error')
        return redirect(url_for('public.index'))

    return decorated_function
