"""
Split Stream - Splits an async stream into two independent streams
"""
import asyncio
from typing import AsyncGenerator, Any, TypeVar
from collections import deque


T = TypeVar('T')


class StreamSplitter:
    """
    Helper class to split an async generator into two independent streams.
    
    This uses queues to buffer chunks and distribute them to both consumers.
    """
    
    def __init__(self, source: AsyncGenerator[T, None]):
        self.source = source
        self.queue1: asyncio.Queue[T | None] = asyncio.Queue()
        self.queue2: asyncio.Queue[T | None] = asyncio.Queue()
        self._feeding_task: asyncio.Task | None = None
        self._started = False
        
    async def _feed_queues(self):
        """Feed chunks from source to both queues"""
        try:
            async for chunk in self.source:
                await self.queue1.put(chunk)
                await self.queue2.put(chunk)
        finally:
            # Signal completion with None
            await self.queue1.put(None)
            await self.queue2.put(None)
    
    def _ensure_started(self):
        """Ensure the feeding task is started"""
        if not self._started:
            self._started = True
            self._feeding_task = asyncio.create_task(self._feed_queues())
    
    async def stream1(self) -> AsyncGenerator[T, None]:
        """First independent stream"""
        self._ensure_started()
        while True:
            chunk = await self.queue1.get()
            if chunk is None:
                break
            yield chunk
    
    async def stream2(self) -> AsyncGenerator[T, None]:
        """Second independent stream"""
        self._ensure_started()
        while True:
            chunk = await self.queue2.get()
            if chunk is None:
                break
            yield chunk


def split_stream(
    stream: AsyncGenerator[T, None]
) -> dict[str, AsyncGenerator[T, None]]:
    """
    Splits an async generator into two independent streams.
    
    This is the Python equivalent of JavaScript's ReadableStream.tee().
    Both resulting streams will receive all chunks from the original stream.
    
    Args:
        stream: The async generator to split
        
    Returns:
        Dictionary containing two independent streams: 'app_stream' and 'util_stream'
        
    Example:
```python
        async def source_stream():
            for i in range(5):
                yield i
                await asyncio.sleep(0.1)
        
        streams = split_stream(source_stream())
        
        async def consume_app():
            async for chunk in streams['app_stream']:
                print(f"App: {chunk}")
        
        async def consume_util():
            async for chunk in streams['util_stream']:
                print(f"Util: {chunk}")
        
        # Both consumers receive all chunks
        await asyncio.gather(consume_app(), consume_util())
```
    """
    splitter = StreamSplitter(stream)
    
    return {
        'app_stream': splitter.stream1(),
        'util_stream': splitter.stream2()
    }