import pymysql
import bcrypt
import jwt
from datetime import datetime, timedelta
from functools import wraps
from flask import request, jsonify
import logging
import secrets

logger = logging.getLogger(__name__)


class AuthHandler:
    def __init__(self, config):
        self.config = config
        self.db_config = {
            'host': config.get('DB_HOST'),
            'port': int(config.get('DB_PORT', 3306)),
            'user': config.get('DB_USER'),
            'password': config.get('DB_PASSWORD'),
            'database': config.get('DB_NAME'),
            'cursorclass': pymysql.cursors.DictCursor
        }
        # JWT secret key - should be in config
        self.jwt_secret = config.get('SECRET_KEY', 'your-secret-key-here-change-in-production')
        self.jwt_algorithm = 'HS256'
        self.jwt_expiration_days = 7
        try:
            self.ensure_embed_tables()
        except Exception as e:
            logger.warning("Could not ensure embed tables at startup (DB may be unreachable): %s", e)

    def get_connection(self):
        """Get database connection"""
        return pymysql.connect(**self.db_config)

    @staticmethod
    def _quote_identifier(identifier):
        return f"`{identifier.replace('`', '``')}`"

    def _table_exists(self, cursor, schema, table_name):
        cursor.execute(
            """SELECT 1
            FROM information_schema.tables
            WHERE table_schema = %s AND table_name = %s
            LIMIT 1""",
            (schema, table_name)
        )
        return cursor.fetchone() is not None

    def _find_template_table(self, cursor, schema, suffix):
        preferred = f"7987_{suffix}"
        cursor.execute(
            """SELECT table_name AS name
            FROM information_schema.tables
            WHERE table_schema = %s AND table_name = %s
            LIMIT 1""",
            (schema, preferred)
        )
        row = cursor.fetchone()
        if row:
            return row['name']

        cursor.execute(
            """SELECT table_name AS name
            FROM information_schema.tables
            WHERE table_schema = %s AND table_name LIKE %s
            ORDER BY table_name
            LIMIT 1""",
            (schema, f"%_{suffix}")
        )
        row = cursor.fetchone()
        return row['name'] if row else None

    def hash_password(self, password):
        """Hash a password using bcrypt"""
        salt = bcrypt.gensalt()
        return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')

    @staticmethod
    def _looks_like_bcrypt_hash(password_hash):
        if not password_hash or not isinstance(password_hash, str):
            return False
        if not password_hash.startswith(("$2a$", "$2b$", "$2y$")):
            return False
        # Typical bcrypt hash length is 60 characters.
        return len(password_hash) >= 50

    def verify_password(self, password, password_hash):
        """Verify a password against its hash"""
        if not self._looks_like_bcrypt_hash(password_hash):
            return False
        try:
            return bcrypt.checkpw(password.encode('utf-8'), password_hash.encode('utf-8'))
        except ValueError:
            # Invalid salt or malformed hash
            return False

    def log_activity(self, user_id, username, activity_type, description=None, ip_address=None, user_agent=None):
        """Log user activity"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """INSERT INTO user_activity_log
                (user_id, username, activity_type, description, ip_address, user_agent)
                VALUES (%s, %s, %s, %s, %s, %s)""",
                (user_id, username, activity_type, description, ip_address, user_agent)
            )
            conn.commit()
        except Exception as e:
            logger.error(f"Error logging activity: {str(e)}")
        finally:
            conn.close()

    def generate_jwt_token(self, user_id, username, email, businesses, is_master=False):
        """Generate a JWT token with user info and accessible businesses"""
        payload = {
            'user_id': user_id,
            'username': username,
            'email': email,
            'businesses': businesses,  # List of {bid, name, role}
            'is_master': is_master,
            'exp': datetime.utcnow() + timedelta(days=self.jwt_expiration_days),
            'iat': datetime.utcnow()
        }
        token = jwt.encode(payload, self.jwt_secret, algorithm=self.jwt_algorithm)
        return token

    def decode_jwt_token(self, token):
        """Decode and validate a JWT token"""
        try:
            payload = jwt.decode(token, self.jwt_secret, algorithms=[self.jwt_algorithm])
            return payload
        except jwt.ExpiredSignatureError:
            return None
        except jwt.InvalidTokenError:
            return None

    def create_user(self, username, email, password, full_name=None, role='user', is_master=False):
        """Create a new user (no business assignment here)"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            role = str(role or 'user').strip().lower()
            if role not in ('user', 'admin'):
                return {'error': 'Invalid role. Use user or admin.'}, 400

            # Check if username or email already exists
            cursor.execute(
                "SELECT id FROM business_users WHERE username = %s OR email = %s",
                (username, email)
            )
            if cursor.fetchone():
                return {'error': 'Username or email already exists'}, 409

            # Hash password
            password_hash = self.hash_password(password)

            # Insert user
            cursor.execute(
                """INSERT INTO business_users
                (username, email, password_hash, plain_password, full_name, role, is_master, is_active)
                VALUES (%s, %s, %s, %s, %s, %s, %s, TRUE)""",
                (username, email, password_hash, password, full_name, role, is_master)
            )
            conn.commit()

            user_id = cursor.lastrowid

            return {
                'id': user_id,
                'username': username,
                'email': email,
                'role': role,
                'is_master': is_master
            }, 201

        except Exception as e:
            conn.rollback()
            logger.error(f"Error creating user: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def assign_business_access(self, user_id, bid, role='user'):
        """Assign business access to a user"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            role = str(role or 'user').strip().lower()
            if role not in ('user', 'admin'):
                return {'error': 'Invalid role. Use user or admin.'}, 400

            # Check if business exists
            cursor.execute("SELECT bid FROM businesses WHERE bid = %s", (bid,))
            if not cursor.fetchone():
                return {'error': 'Business not found'}, 404

            # Check if user exists
            cursor.execute("SELECT id FROM business_users WHERE id = %s", (user_id,))
            if not cursor.fetchone():
                return {'error': 'User not found'}, 404

            # Insert access
            cursor.execute(
                """INSERT INTO user_business_access (user_id, bid, role)
                VALUES (%s, %s, %s)
                ON DUPLICATE KEY UPDATE role = %s""",
                (user_id, bid, role, role)
            )
            conn.commit()

            return {'message': 'Business access granted', 'user_id': user_id, 'bid': bid, 'role': role}, 200

        except Exception as e:
            conn.rollback()
            logger.error(f"Error assigning business access: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def get_user_businesses(self, user_id):
        """Get all businesses accessible to a user"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            cursor.execute(
                """SELECT b.bid, b.name, b.description, uba.role
                FROM user_business_access uba
                JOIN businesses b ON uba.bid = b.bid
                WHERE uba.user_id = %s AND b.is_active = TRUE
                ORDER BY b.name""",
                (user_id,)
            )
            businesses = cursor.fetchall()
            return businesses

        except Exception as e:
            logger.error(f"Error getting user businesses: {str(e)}")
            return []
        finally:
            conn.close()

    def login(self, username, password, ip_address=None, user_agent=None):
        """Authenticate user and create JWT token"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            # Get user by username or email
            cursor.execute(
                """SELECT id, username, email, password_hash, plain_password, full_name,
                role, is_master, is_active
                FROM business_users
                WHERE (username = %s OR email = %s) AND is_active = TRUE""",
                (username, username)
            )
            user = cursor.fetchone()

            if not user:
                return {'error': 'Invalid credentials'}, 401

            # Verify password
            password_ok = self.verify_password(password, user.get('password_hash'))
            needs_upgrade = False

            if not password_ok:
                plain_password = user.get('plain_password')
                if plain_password and password == plain_password:
                    password_ok = True
                    needs_upgrade = True
                elif user.get('password_hash') and password == user.get('password_hash'):
                    # Handle legacy rows where password_hash stores plain text
                    password_ok = True
                    needs_upgrade = True

            if not password_ok:
                return {'error': 'Invalid credentials'}, 401

            if needs_upgrade:
                new_hash = self.hash_password(password)
                cursor.execute(
                    "UPDATE business_users SET password_hash = %s WHERE id = %s",
                    (new_hash, user['id'])
                )
                logger.warning(
                    "Upgraded password hash for user %s due to legacy/invalid hash",
                    user['username']
                )

            # Get user's accessible businesses
            businesses = self.get_user_businesses(user['id'])

            # For master users, they can access all businesses
            if user['is_master']:
                cursor.execute(
                    """SELECT bid, name, description, 'admin' as role
                    FROM businesses
                    WHERE is_active = TRUE
                    ORDER BY name"""
                )
                businesses = cursor.fetchall()

            # Update last login
            cursor.execute(
                "UPDATE business_users SET last_login = NOW() WHERE id = %s",
                (user['id'],)
            )
            conn.commit()

            # Generate JWT token
            token = self.generate_jwt_token(
                user_id=user['id'],
                username=user['username'],
                email=user['email'],
                businesses=businesses,
                is_master=user['is_master']
            )

            # Log login activity
            self.log_activity(
                user_id=user['id'],
                username=user['username'],
                activity_type='login',
                description=f"User {user['username']} logged in successfully",
                ip_address=ip_address,
                user_agent=user_agent
            )

            return {
                'token': token,
                'user': {
                    'id': user['id'],
                    'username': user['username'],
                    'email': user['email'],
                    'full_name': user['full_name'],
                    'role': user['role'],
                    'is_master': user['is_master'],
                    'businesses': businesses
                }
            }, 200

        except Exception as e:
            conn.rollback()
            logger.error(f"Error during login: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def validate_token(self, token):
        """Validate a JWT token and return user info"""
        payload = self.decode_jwt_token(token)
        if not payload:
            return None

        return {
            'id': payload.get('user_id'),
            'username': payload.get('username'),
            'email': payload.get('email'),
            'businesses': payload.get('businesses', []),
            'is_master': payload.get('is_master', False)
        }

    def logout(self, token):
        """Logout user (with JWT, we just rely on token expiration)"""
        # With JWT, logout is handled client-side by removing the token
        # We could implement a token blacklist here if needed
        return {'message': 'Logged out successfully'}, 200

    def change_password(self, user_id, current_password, new_password):
        """Change a user's password after verifying the current one"""
        if not new_password or len(new_password) < 6:
            return {'error': 'New password must be at least 6 characters'}, 400
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                "SELECT password_hash, plain_password FROM business_users WHERE id = %s AND is_active = TRUE",
                (user_id,)
            )
            user = cursor.fetchone()
            if not user:
                return {'error': 'User not found'}, 404

            password_ok = self.verify_password(current_password, user.get('password_hash'))
            if not password_ok:
                plain = user.get('plain_password')
                if plain and current_password == plain:
                    password_ok = True
            if not password_ok:
                return {'error': 'Current password is incorrect'}, 401

            new_hash = self.hash_password(new_password)
            cursor.execute(
                "UPDATE business_users SET password_hash = %s, plain_password = %s WHERE id = %s",
                (new_hash, new_password, user_id)
            )
            conn.commit()
            return {'message': 'Password changed successfully'}, 200
        except Exception as e:
            conn.rollback()
            logger.error(f"Error changing password: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def update_profile(self, user_id, full_name):
        """Update a user's profile details"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                "UPDATE business_users SET full_name = %s WHERE id = %s AND is_active = TRUE",
                (full_name, user_id)
            )
            conn.commit()
            if cursor.rowcount == 0:
                return {'error': 'User not found'}, 404
            return {'message': 'Profile updated successfully'}, 200
        except Exception as e:
            conn.rollback()
            logger.error(f"Error updating profile: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def get_all_users(self):
        """Get all users (master admin only)"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """SELECT id, username, email, plain_password, full_name, role, is_master, is_active,
                created_at, last_login
                FROM business_users
                ORDER BY created_at DESC"""
            )
            users = cursor.fetchall()

            # Get businesses for each user
            for user in users:
                user['businesses'] = self.get_user_businesses(user['id'])

            return users, 200
        except Exception as e:
            logger.error(f"Error getting users: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def get_users_by_business(self, bid):
        """Get users assigned to a specific business (bid)."""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT
                    bu.id,
                    bu.username,
                    bu.email,
                    bu.full_name,
                    bu.role,
                    bu.is_master,
                    bu.is_active,
                    uba.role AS business_role
                FROM user_business_access uba
                JOIN business_users bu ON bu.id = uba.user_id
                WHERE uba.bid = %s
                  AND bu.is_active = TRUE
                ORDER BY bu.created_at DESC
                """,
                (str(bid),)
            )
            users = cursor.fetchall()

            # Normalize shape for frontend usage.
            normalized = []
            for u in users:
                full_name = (u.get("full_name") or "").strip()
                username = (u.get("username") or "").strip()
                normalized.append({
                    "id": u.get("id"),
                    "username": username,
                    "email": u.get("email"),
                    "full_name": full_name,
                    "name": full_name or username,
                    # `role` here is the role within this business (`admin`/`user`)
                    "role": (u.get("business_role") or u.get("role") or "user"),
                    "is_master": u.get("is_master"),
                    "is_active": u.get("is_active"),
                    "status": "Active" if u.get("is_active") else "Inactive",
                })

            return normalized, 200
        except Exception as e:
            logger.error(f"Error getting users by business: {str(e)}")
            return {"error": str(e)}, 500
        finally:
            conn.close()

    def create_business(self, bid, name, description=None):
        """Create a new business (master admin only)"""
        bid = str(bid)
        conn = self.get_connection()
        created_tables = []
        try:
            cursor = conn.cursor()

            # Check if business already exists
            cursor.execute("SELECT bid FROM businesses WHERE bid = %s", (bid,))
            if cursor.fetchone():
                return {'error': 'Business ID already exists'}, 409

            schema = self.db_config['database']
            suffixes = ['raw_calls', 'sarvamresponse', 'callanalytics']
            templates = {}

            for suffix in suffixes:
                template = self._find_template_table(cursor, schema, suffix)
                if not template:
                    return {'error': f'No template table found for {suffix}'}, 500
                templates[suffix] = template

            for suffix in suffixes:
                table_name = f"{bid}_{suffix}"
                if self._table_exists(cursor, schema, table_name):
                    return {'error': f'Table {table_name} already exists'}, 409

            for suffix in suffixes:
                table_name = f"{bid}_{suffix}"
                template = templates[suffix]
                cursor.execute(
                    f"CREATE TABLE {self._quote_identifier(table_name)} "
                    f"LIKE {self._quote_identifier(template)}"
                )
                created_tables.append(table_name)

            cursor.execute(
                """INSERT INTO businesses (bid, name, description, is_active)
                VALUES (%s, %s, %s, TRUE)""",
                (bid, name, description)
            )
            conn.commit()

            return {
                'bid': bid,
                'name': name,
                'description': description
            }, 201

        except pymysql.IntegrityError:
            conn.rollback()
            return {'error': 'Business ID already exists'}, 409
        except Exception as e:
            conn.rollback()
            logger.error(f"Error creating business: {str(e)}")
            if created_tables:
                try:
                    cleanup_cursor = conn.cursor()
                    for table_name in created_tables:
                        cleanup_cursor.execute(
                            f"DROP TABLE IF EXISTS {self._quote_identifier(table_name)}"
                        )
                    conn.commit()
                except Exception as cleanup_error:
                    logger.error(f"Error cleaning up tables: {str(cleanup_error)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def get_all_businesses(self):
        """Get all businesses"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """SELECT bid, name, description, is_active, created_at
                FROM businesses
                ORDER BY name"""
            )
            businesses = cursor.fetchall()
            return businesses, 200
        except Exception as e:
            logger.error(f"Error getting businesses: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def get_activity_log(self, limit=100, user_id=None, activity_type=None):
        """Get activity log entries"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            
            query = """SELECT al.id, al.user_id, al.username, al.activity_type, 
                       al.description, al.ip_address, al.user_agent, al.created_at,
                       bu.email, bu.full_name
                FROM user_activity_log al
                LEFT JOIN business_users bu ON al.user_id = bu.id
                WHERE 1=1"""
            params = []
            
            if user_id:
                query += " AND al.user_id = %s"
                params.append(user_id)
                
            if activity_type:
                query += " AND al.activity_type = %s"
                params.append(activity_type)
                
            query += " ORDER BY al.created_at DESC LIMIT %s"
            params.append(limit)
            
            cursor.execute(query, params)
            logs = cursor.fetchall()
            
            return logs, 200
        except Exception as e:
            logger.error(f"Error getting activity log: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()


    # =========================================================================
    # EMBED / IFRAME INTEGRATION
    # =========================================================================

    def ensure_embed_tables(self):
        """Create embed_api_keys table if it doesn't exist"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS embed_api_keys (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    api_key VARCHAR(64) UNIQUE NOT NULL,
                    bid VARCHAR(20) NOT NULL,
                    partner_name VARCHAR(100) NOT NULL,
                    allowed_origins TEXT DEFAULT NULL,
                    is_active TINYINT(1) DEFAULT 1,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    expires_at TIMESTAMP NULL DEFAULT NULL,
                    last_used_at TIMESTAMP NULL DEFAULT NULL,
                    INDEX idx_api_key (api_key),
                    INDEX idx_bid (bid)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            """)
            conn.commit()
            logger.info("embed_api_keys table ensured")
        except Exception as e:
            logger.error(f"Error ensuring embed tables: {str(e)}")
        finally:
            conn.close()

    @staticmethod
    def generate_api_key():
        """Generate a unique API key for embed access"""
        return "sk_embed_" + secrets.token_hex(24)

    def create_embed_api_key(self, bid, partner_name, allowed_origins=None, expires_at=None):
        """Create a new embed API key for a business"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            # Check if business exists
            cursor.execute("SELECT bid FROM businesses WHERE bid = %s", (bid,))
            if not cursor.fetchone():
                return {'error': 'Business not found'}, 404

            api_key = self.generate_api_key()

            cursor.execute(
                """INSERT INTO embed_api_keys
                (api_key, bid, partner_name, allowed_origins, expires_at)
                VALUES (%s, %s, %s, %s, %s)""",
                (api_key, bid, partner_name, allowed_origins, expires_at)
            )
            conn.commit()

            return {
                'id': cursor.lastrowid,
                'api_key': api_key,
                'bid': bid,
                'partner_name': partner_name,
                'allowed_origins': allowed_origins,
                'expires_at': str(expires_at) if expires_at else None
            }, 201

        except Exception as e:
            conn.rollback()
            logger.error(f"Error creating embed API key: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def list_embed_api_keys(self, bid=None):
        """List all embed API keys, optionally filtered by bid"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            if bid:
                cursor.execute(
                    """SELECT ek.id, ek.api_key, ek.bid, b.name as business_name,
                       ek.partner_name, ek.allowed_origins, ek.is_active,
                       ek.created_at, ek.expires_at, ek.last_used_at
                    FROM embed_api_keys ek
                    LEFT JOIN businesses b ON ek.bid = b.bid
                    WHERE ek.bid = %s
                    ORDER BY ek.created_at DESC""",
                    (bid,)
                )
            else:
                cursor.execute(
                    """SELECT ek.id, ek.api_key, ek.bid, b.name as business_name,
                       ek.partner_name, ek.allowed_origins, ek.is_active,
                       ek.created_at, ek.expires_at, ek.last_used_at
                    FROM embed_api_keys ek
                    LEFT JOIN businesses b ON ek.bid = b.bid
                    ORDER BY ek.created_at DESC"""
                )

            keys = cursor.fetchall()

            # Mask API keys - only show last 8 chars
            for key in keys:
                full_key = key['api_key']
                key['api_key_masked'] = '***' + full_key[-8:]
                del key['api_key']

            return keys, 200

        except Exception as e:
            logger.error(f"Error listing embed API keys: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def revoke_embed_api_key(self, key_id):
        """Revoke (deactivate) an embed API key"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            cursor.execute(
                "UPDATE embed_api_keys SET is_active = 0 WHERE id = %s",
                (key_id,)
            )
            conn.commit()

            if cursor.rowcount == 0:
                return {'error': 'API key not found'}, 404

            return {'message': 'API key revoked successfully'}, 200

        except Exception as e:
            conn.rollback()
            logger.error(f"Error revoking embed API key: {str(e)}")
            return {'error': str(e)}, 500
        finally:
            conn.close()

    def validate_api_key(self, api_key, bid):
        """Validate an embed API key for a specific business"""
        conn = self.get_connection()
        try:
            cursor = conn.cursor()

            cursor.execute(
                """SELECT id, api_key, bid, partner_name, allowed_origins, expires_at
                FROM embed_api_keys
                WHERE api_key = %s AND bid = %s AND is_active = 1""",
                (api_key, bid)
            )
            key_record = cursor.fetchone()

            if not key_record:
                return None

            # Check expiry
            if key_record['expires_at'] and key_record['expires_at'] < datetime.utcnow():
                return None

            # Update last_used_at
            cursor.execute(
                "UPDATE embed_api_keys SET last_used_at = NOW() WHERE id = %s",
                (key_record['id'],)
            )
            conn.commit()

            return key_record

        except Exception as e:
            logger.error(f"Error validating API key: {str(e)}")
            return None
        finally:
            conn.close()

    def generate_embed_token(self, bid, partner_name, api_key_id):
        """Generate a short-lived JWT token for iframe embedding"""
        payload = {
            'type': 'embed',
            'bid': str(bid),
            'partner_name': partner_name,
            'api_key_id': api_key_id,
            'exp': datetime.utcnow() + timedelta(hours=1),
            'iat': datetime.utcnow()
        }
        token = jwt.encode(payload, self.jwt_secret, algorithm=self.jwt_algorithm)
        return token

    def validate_embed_token(self, token):
        """Validate an embed JWT token"""
        try:
            payload = jwt.decode(token, self.jwt_secret, algorithms=[self.jwt_algorithm])

            if payload.get('type') != 'embed':
                return None

            return {
                'bid': payload.get('bid'),
                'partner_name': payload.get('partner_name'),
                'api_key_id': payload.get('api_key_id')
            }
        except jwt.ExpiredSignatureError:
            logger.warning("Embed token expired")
            return None
        except jwt.InvalidTokenError:
            logger.warning("Invalid embed token")
            return None


def require_auth(f):
    """Decorator to require authentication for routes"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Get token from Authorization header
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return jsonify({'error': 'Missing or invalid authorization header'}), 401

        token = auth_header.replace('Bearer ', '')

        # Validate token
        from flask import current_app
        auth_handler = current_app.auth_handler
        user = auth_handler.validate_token(token)

        if not user:
            return jsonify({'error': 'Invalid or expired token'}), 401

        # Add user to request context
        request.current_user = user

        return f(*args, **kwargs)

    return decorated_function


def require_master(f):
    """Decorator to require master admin access"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        user = request.current_user
        if not user.get('is_master'):
            return jsonify({'error': 'Master admin access required'}), 403
        return f(*args, **kwargs)
    return decorated_function


def require_business_access(f):
    """Decorator to ensure user has access to the requested business"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # This assumes the route has a 'bid' parameter
        bid = kwargs.get('bid') or request.view_args.get('bid')
        user = request.current_user

        # Master admins can access all businesses
        if user.get('is_master'):
            return f(*args, **kwargs)

        # Check if user has access to this business
        user_businesses = [b['bid'] for b in user.get('businesses', [])]
        if bid not in user_businesses:
            return jsonify({'error': 'Access denied to this business'}), 403

        return f(*args, **kwargs)

    return decorated_function
