"""
ID Generation utilities for the application.
"""

import string
import random
import uuid
import time
from typing import Optional, Literal


def generate_id(
    id_type: Literal['customer', 'uin', 'merchant', 'user', 'transaction', 'invoice', 'contact'],
    name: Optional[str] = None
) -> str:
    """Generate a unique ID based on the specified type.
    
    All generated IDs are guaranteed to be exactly 15 characters long.
    
    Args:
        id_type: The type of ID to generate ('customer', 'uin', 'merchant', 'user', 'transaction', 'invoice', 'contact')
        name: Optional name to base the ID on
        
    Returns:
        A unique alphanumeric ID with the appropriate prefix and format (exactly 15 characters)
        
    Examples:
        generate_id('customer', 'John Doe') → 'ACCJOH123456789' (15 chars)
        generate_id('uin', 'Jane Smith') → 'UINJAN1234567890' (15 chars)
        generate_id('merchant', 'Test Corp') → 'MERTES123456789' (15 chars)
        generate_id('contact', 'John Doe') → 'CONJOH123456789' (15 chars)
        generate_id('transaction') → 'TXN12345678ABCD' (15 chars)
    """
    # Define prefixes - calculate remaining length dynamically
    prefixes = {
        'customer': 'ACC',    
        'uin': 'UIN',         
        'merchant': 'MER',    
        'user': 'USR',        
        'transaction': 'TXN', 
        'invoice': 'INV',
        'contact': 'CON'      
    }
    
    if id_type not in prefixes:
        raise ValueError(f"Unsupported ID type: {id_type}. Supported types: {list(prefixes.keys())}")
    
    prefix = prefixes[id_type]
    remaining_length = 15 - len(prefix)  # Always 12 chars remaining
    
    # For name-based IDs: use 3 chars from name + 9 chars timestamp+uuid
    # For non-name IDs: use all 12 chars for timestamp+uuid
    if id_type in ['customer', 'uin', 'merchant', 'user', 'contact'] and name:
        # Use 3 chars from name, 9 remaining for timestamp+uuid
        stripped_name = name.replace(" ", "").upper()[:3]
        if len(stripped_name) < 3:
            stripped_name = stripped_name.ljust(3, 'X')
        name_part = stripped_name
        
        # 9 chars remaining: 6 timestamp + 3 uuid
        timestamp_part = str(int(time.time() * 1000))[-6:]
        uuid_part = uuid.uuid4().hex[:3].upper()
        
        generated_id = f"{prefix}{name_part}{timestamp_part}{uuid_part}"
    else:
        # Use all 12 chars for timestamp+uuid (no name part)
        # 12 chars: 8 timestamp + 4 uuid for better uniqueness
        timestamp_part = str(int(time.time() * 1000))[-8:]
        uuid_part = uuid.uuid4().hex[:4].upper()
        
        generated_id = f"{prefix}{timestamp_part}{uuid_part}"
    
    # Validate that the generated ID is exactly 15 characters
    if len(generated_id) != 15:
        raise ValueError(f"Generated ID '{generated_id}' has length {len(generated_id)}, expected 15 characters.")
    
    return generated_id


