from typing import Optional, Union, List
import aiohttp
from urllib.parse import urlencode

from ..types.assets import (
    Asset,
    AssetFilter,
    ResolveAssetOptions,
    AssetPresignedUrl,
    validate_hash
)
from .asset_utils import get_endpoint_and_token, create_request, create_json_request

async def list_assets(filter: Optional[AssetFilter] = None) -> List[Asset]:
    """
    List assets with optional filtering.

    Args:
        filter: Optional filter by type and/or hash

    Returns:
        List of assets matching the filter
    """
    filter = filter or {}
    path = '/assets'
    if filter:
        path = f"{path}?{urlencode(filter)}"

    return await create_json_request(path)

async def resolve_asset(hash: str, options: Optional[ResolveAssetOptions] = None) -> Union[aiohttp.StreamReader, bytes]:
    """
    Resolve an asset by its sha256 hash and return a stream or buffer of data.

    Args:
        hash: Content-addressed hash (sha256:<hex>)
        options: Optional configuration including as_buffer flag

    Returns:
        Either an aiohttp.StreamReader for streaming or bytes for buffer

    Raises:
        ValueError: If the hash format is invalid
        RuntimeError: If environment variables are not set
        aiohttp.ClientError: If the HTTP request fails
    """
    options = options or {}
    validate_hash(hash)

    timeout = aiohttp.ClientTimeout(total=300)  # 5 minutes timeout for large files
    async with aiohttp.ClientSession(timeout=timeout) as session:
        endpoint, token = get_endpoint_and_token()
        url = f"{endpoint}/assets/{hash}/download"
        headers = {'Authorization': f'Bearer {token}'}

        async with session.get(url, headers=headers) as response:
            if response.status >= 400:
                error_text = await response.text()
                raise aiohttp.ClientError(f'Request failed: {response.status} {error_text}')

            if options.get('as_buffer', False):
                return await response.read()

            return response.content

def get_asset_download_url(hash: str) -> str:
    """Get the direct download URL for an asset by its sha256 hash."""
    validate_hash(hash)
    endpoint, _ = get_endpoint_and_token()
    return f"{endpoint}/assets/{hash}/download"

async def get_asset_presigned_url(hash: str) -> AssetPresignedUrl:
    """
    Get a presigned URL for an asset by its sha256 hash.

    Args:
        hash: Content-addressed hash (sha256:<hex>)

    Returns:
        Dict containing the presigned URL and its expiration time

    Raises:
        ValueError: If the hash format is invalid
        RuntimeError: If environment variables are not set
        aiohttp.ClientError: If the HTTP request fails
    """
    validate_hash(hash)
    return await create_json_request(f"/assets/{hash}/presigned")

async def asset_exists(hash: str) -> bool:
    """
    Check if an asset exists on NanoCore by its sha256 hash.

    Args:
        hash: Content-addressed hash (sha256:<hex>)

    Returns:
        True if the asset exists
    """
    validate_hash(hash)
    try:
        result = await create_json_request(f"/assets/{hash}/exists")
        return result.get('exists', False)
    except Exception:
        return False
