"""
JSON Data Access Layer
Provides data operations using JSON files
"""
import json
import os
from werkzeug.security import generate_password_hash
from threading import Lock

# File paths
basedir = os.path.abspath(os.path.dirname(__file__))
USERS_FILE = os.path.join(basedir, 'data', 'users.json')
PRODUCTS_FILE = os.path.join(basedir, 'data', 'products.json')
PRODUCT_ATTRIBUTES_FILE = os.path.join(basedir, 'data', 'product_attributes.json')

# Thread locks for file operations
users_lock = Lock()
products_lock = Lock()
attributes_lock = Lock()

# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

def _load_json_file(filepath):
    """Load a JSON file"""
    if os.path.exists(filepath):
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                return json.load(f)
        except:
            return []
    return []

def _save_json_file(filepath, data):
    """Save data to a JSON file"""
    os.makedirs(os.path.dirname(filepath), exist_ok=True)
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(data, f, indent=2)

def _find_user_by_username(users, username):
    """Find user index by username"""
    for i, user in enumerate(users):
        if user['username'] == username:
            return i, user
    return None, None

def _find_product_by_code(products, product_code):
    """Find product index by code"""
    for i, product in enumerate(products):
        if product['productCode'] == product_code:
            return i, product
    return None, None

# ============================================================================
# USER OPERATIONS
# ============================================================================

def get_user_by_username(username):
    """Get a user by username"""
    with users_lock:
        users = _load_json_file(USERS_FILE)
        _, user = _find_user_by_username(users, username)
        return user

def get_user_by_id(user_id):
    """Get a user by ID (array index in JSON)"""
    with users_lock:
        users = _load_json_file(USERS_FILE)
        if 0 <= user_id < len(users):
            return users[user_id]
        return None

def get_all_users():
    """Get all users"""
    with users_lock:
        return _load_json_file(USERS_FILE)

def create_user(user_data):
    """
    Create a new user
    
    Args:
        user_data (dict): User data with keys: username, password, defaultLocation, 
                         locationSettings, permissions, active
    
    Returns:
        dict: Created user as dictionary or None if username exists
    """
    with users_lock:
        users = _load_json_file(USERS_FILE)
        
        # Check if username already exists
        if any(user['username'] == user_data['username'] for user in users):
            return None
        
        # Hash password if not already hashed
        password = user_data['password']
        if not password.startswith('pbkdf2:'):
            password = generate_password_hash(password, method='pbkdf2:sha256')
        
        # Get location settings
        location_settings = user_data.get('locationSettings', {})
        default_location = user_data['defaultLocation']
        
        # Ensure default location is accessible
        if default_location not in location_settings:
            location_settings[default_location] = {}
        location_settings[default_location]['accessible'] = True
        
        # Create new user
        new_user = {
            'username': user_data['username'],
            'password': password,
            'defaultLocation': default_location,
            'locationSettings': location_settings,
            'permissions': user_data.get('permissions', {}),
            'active': user_data.get('active', True)
        }
        
        if user_data.get('superAdmin'):
            new_user['superAdmin'] = True
        
        users.append(new_user)
        _save_json_file(USERS_FILE, users)
        
        return new_user

def update_user(user_id, user_data):
    """
    Update an existing user
    
    Args:
        user_id (int): User ID (array index)
        user_data (dict): Updated user data
    
    Returns:
        dict: Updated user as dictionary or None if not found
    """
    with users_lock:
        users = _load_json_file(USERS_FILE)
        
        if user_id < 0 or user_id >= len(users):
            return None
        
        user = users[user_id]
        
        # Update fields
        if 'defaultLocation' in user_data:
            user['defaultLocation'] = user_data['defaultLocation']
        if 'active' in user_data:
            user['active'] = user_data['active']
        if 'superAdmin' in user_data:
            user['superAdmin'] = user_data['superAdmin']
        if 'locationSettings' in user_data:
            user['locationSettings'] = user_data['locationSettings']
        if 'permissions' in user_data:
            user['permissions'] = user_data['permissions']
        if 'password' in user_data:
            password = user_data['password']
            if not password.startswith('pbkdf2:'):
                password = generate_password_hash(password, method='pbkdf2:sha256')
            user['password'] = password
        
        _save_json_file(USERS_FILE, users)
        return user

def delete_user(user_id):
    """
    Delete a user
    
    Args:
        user_id (int): User ID (array index)
    
    Returns:
        bool: True if deleted, False if not found
    """
    with users_lock:
        users = _load_json_file(USERS_FILE)
        
        if user_id < 0 or user_id >= len(users):
            return False
        
        users.pop(user_id)
        _save_json_file(USERS_FILE, users)
        return True

def toggle_user_active(user_id, active):
    """
    Toggle user active status
    
    Args:
        user_id (int): User ID (array index)
        active (bool): Active status
    
    Returns:
        dict: Updated user or None if not found
    """
    with users_lock:
        users = _load_json_file(USERS_FILE)
        
        if user_id < 0 or user_id >= len(users):
            return None
        
        users[user_id]['active'] = active
        _save_json_file(USERS_FILE, users)
        return users[user_id]

def change_user_password(user_id, new_password):
    """
    Change a user's password
    
    Args:
        user_id (int): User ID (array index)
        new_password (str): New password (will be hashed)
    
    Returns:
        dict: Updated user or None if not found
    """
    with users_lock:
        users = _load_json_file(USERS_FILE)
        
        if user_id < 0 or user_id >= len(users):
            return None
        
        hashed_password = generate_password_hash(new_password, method='pbkdf2:sha256')
        users[user_id]['password'] = hashed_password
        _save_json_file(USERS_FILE, users)
        return users[user_id]

# ============================================================================
# PRODUCT OPERATIONS
# ============================================================================

def get_all_products(location=None):
    """
    Get all products, optionally filtered by location
    
    Args:
        location (str, optional): Filter by location code
    
    Returns:
        list: List of product dictionaries
    """
    with products_lock:
        products = _load_json_file(PRODUCTS_FILE)
        
        if location:
            products = [p for p in products if p.get('location') == location]
        
        return products

def get_product_by_code(product_code):
    """
    Get a product by its product code
    
    Args:
        product_code (str): Product code
    
    Returns:
        dict: Product dictionary or None if not found
    """
    with products_lock:
        products = _load_json_file(PRODUCTS_FILE)
        _, product = _find_product_by_code(products, product_code)
        return product

def create_product(product_data):
    """
    Create a new product
    
    Args:
        product_data (dict): Product data
    
    Returns:
        dict: Created product or None if code exists
    """
    with products_lock:
        products = _load_json_file(PRODUCTS_FILE)
        
        # Check if product already exists
        if any(p['productCode'] == product_data['productCode'] for p in products):
            return None
        
        # Create product with normalized structure
        new_product = {
            'id': product_data['productCode'],
            'productCode': product_data['productCode'],
            'category': product_data.get('category'),
            'description': product_data.get('description'),
            'discontinued': product_data.get('discontinued', False),
            'location': product_data.get('location'),
            'baseType': product_data.get('baseType', ''),
            'subType': product_data.get('subType', {}),
            'materials': product_data.get('materials', []),
            'colors': product_data.get('colors', []),
            'isAccessory': product_data.get('isAccessory', False),
            'compatibleAccessories': product_data.get('compatibleAccessories', []),
            'imageConfig': product_data.get('imageConfig', {})
        }
        
        products.append(new_product)
        _save_json_file(PRODUCTS_FILE, products)
        
        return new_product

def update_product(product_code, product_data):
    """
    Update an existing product
    
    Args:
        product_code (str): Product code
        product_data (dict): Updated product data
    
    Returns:
        dict: Updated product or None if not found
    """
    with products_lock:
        products = _load_json_file(PRODUCTS_FILE)
        index, product = _find_product_by_code(products, product_code)
        
        if product is None:
            return None
        
        # Update fields
        if 'category' in product_data:
            product['category'] = product_data['category']
        if 'description' in product_data:
            product['description'] = product_data['description']
        if 'discontinued' in product_data:
            product['discontinued'] = product_data['discontinued']
        if 'location' in product_data:
            product['location'] = product_data['location']
        if 'baseType' in product_data:
            product['baseType'] = product_data['baseType']
        if 'isAccessory' in product_data:
            product['isAccessory'] = product_data['isAccessory']
        if 'subType' in product_data:
            product['subType'] = product_data['subType']
        if 'materials' in product_data:
            product['materials'] = product_data['materials']
        if 'colors' in product_data:
            product['colors'] = product_data['colors']
        if 'compatibleAccessories' in product_data:
            product['compatibleAccessories'] = product_data['compatibleAccessories']
        if 'imageConfig' in product_data:
            product['imageConfig'] = product_data['imageConfig']
        
        _save_json_file(PRODUCTS_FILE, products)
        return product

def delete_product(product_code):
    """
    Delete a product
    
    Args:
        product_code (str): Product code
    
    Returns:
        bool: True if deleted, False if not found
    """
    with products_lock:
        products = _load_json_file(PRODUCTS_FILE)
        index, _ = _find_product_by_code(products, product_code)
        
        if index is None:
            return False
        
        products.pop(index)
        _save_json_file(PRODUCTS_FILE, products)
        return True

# ============================================================================
# LOCATION OPERATIONS
# ============================================================================

def get_all_locations():
    """Get all locations"""
    attributes = _load_json_file(PRODUCT_ATTRIBUTES_FILE)
    return attributes.get('locations', [])

def get_location_by_code(code):
    """Get a location by code"""
    locations = get_all_locations()
    for loc in locations:
        if loc['code'] == code:
            return loc
    return None

# ============================================================================
# PRODUCT ATTRIBUTES OPERATIONS
# ============================================================================

def get_product_attributes():
    """
    Get product attributes configuration
    
    Returns:
        dict: Attributes with locations, statuses, productTypes, codeModifiers
    """
    with attributes_lock:
        attributes = _load_json_file(PRODUCT_ATTRIBUTES_FILE)
        
        if not attributes:
            return {
                'locations': [],
                'statuses': [],
                'productTypes': [],
                'codeModifiers': []
            }
        
        return attributes

def update_product_attributes(attributes_data):
    """
    Update product attributes configuration
    
    Args:
        attributes_data (dict): Updated attributes
    
    Returns:
        dict: Updated attributes
    """
    with attributes_lock:
        attributes = _load_json_file(PRODUCT_ATTRIBUTES_FILE)
        
        if 'statuses' in attributes_data:
            attributes['statuses'] = attributes_data['statuses']
        if 'productTypes' in attributes_data:
            attributes['productTypes'] = attributes_data['productTypes']
        if 'codeModifiers' in attributes_data:
            attributes['codeModifiers'] = attributes_data['codeModifiers']
        if 'locations' in attributes_data:
            attributes['locations'] = attributes_data['locations']
        
        _save_json_file(PRODUCT_ATTRIBUTES_FILE, attributes)
        return attributes

# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

def commit():
    """No-op for JSON (writes are immediate)"""
    pass

def rollback():
    """No-op for JSON (no transactions)"""
    pass
