"""
Cache key generation utilities
"""
import hashlib
import json
from typing import Any, List, Optional


def generate_cache_key(cache_type: str, key_params: Optional[List[str]], args: tuple, kwargs: dict) -> str:
    """
    Generate cache key from function parameters

    Format: "{cache_type}:{param1_value}:{param2_value}:..."

    Args:
        cache_type: Type of cache (e.g., 'dashboard_summary', 'invoices')
        key_params: List of parameter names to include in key
        args: Positional arguments from function call
        kwargs: Keyword arguments from function call

    Returns:
        Cache key string

    Examples:
        generate_cache_key('schema', ['company_id'], (123,), {})
        -> "schema:123"

        generate_cache_key('dashboard_summary', ['company', 'username'], (), {'company': '123', 'username': 'john'})
        -> "dashboard_summary:123:john"

        generate_cache_key('invoices', ['company', 'invoice_type', 'status'], (123, 'CLIENTI', 'neplatite'), {})
        -> "invoices:123:CLIENTI:neplatite"
    """
    key_parts = [cache_type]

    if not key_params:
        # No specific params - use all args/kwargs (fallback)
        if args:
            key_parts.extend([str(arg) for arg in args])
        if kwargs:
            # Sort kwargs for consistent key generation
            sorted_kwargs = sorted(kwargs.items())
            key_parts.extend([f"{k}={v}" for k, v in sorted_kwargs])
    else:
        # Extract specific params
        for i, param_name in enumerate(key_params):
            # Try to get from kwargs first
            if param_name in kwargs:
                value = kwargs[param_name]
            # Then try positional args
            elif i < len(args):
                value = args[i]
            else:
                # Parameter not found - use placeholder
                value = "none"

            key_parts.append(str(value))

    return ":".join(key_parts)


def generate_key_pattern(cache_type: str, company_id: Optional[int] = None) -> str:
    """
    Generate cache key pattern for matching multiple keys

    Used for invalidation by type or company

    Args:
        cache_type: Type of cache
        company_id: Optional company ID to filter by

    Returns:
        Pattern string (prefix)

    Examples:
        generate_key_pattern('dashboard_summary')
        -> "dashboard_summary:"

        generate_key_pattern('dashboard_summary', 123)
        -> "dashboard_summary:123"
    """
    if company_id is not None:
        return f"{cache_type}:{company_id}"
    return f"{cache_type}:"


def hash_complex_params(params: dict) -> str:
    """
    Generate hash for complex parameters (e.g., filters, queries)

    Used when cache key would be too long with full param values

    Args:
        params: Dictionary of parameters to hash

    Returns:
        8-character hash string

    Example:
        filters = {'status': 'neplatite', 'date_from': '2024-01-01', 'date_to': '2024-12-31'}
        hash_complex_params(filters)
        -> "a3f8b2c1"
    """
    # Sort keys for consistent hashing
    sorted_params = json.dumps(params, sort_keys=True)
    hash_obj = hashlib.sha256(sorted_params.encode())
    # Return first 8 characters of hex digest
    return hash_obj.hexdigest()[:8]


def extract_company_id_from_key(cache_key: str) -> Optional[int]:
    """
    Extract company_id from cache key

    Assumes format: "cache_type:company_id:..."

    Args:
        cache_key: Cache key string

    Returns:
        Company ID or None if not found

    Example:
        extract_company_id_from_key("dashboard_summary:123:john")
        -> 123
    """
    parts = cache_key.split(":")
    if len(parts) >= 2:
        try:
            return int(parts[1])
        except (ValueError, TypeError):
            pass
    return None


def extract_cache_type_from_key(cache_key: str) -> str:
    """
    Extract cache_type from cache key

    Args:
        cache_key: Cache key string

    Returns:
        Cache type (first part before colon)

    Example:
        extract_cache_type_from_key("dashboard_summary:123:john")
        -> "dashboard_summary"
    """
    return cache_key.split(":")[0]
