"""0G Storage Python SDK."""

import logging

from .contracts import (
    FlowContractClient,
    MarketContractClient,
    Submission,
    SubmissionData,
    SubmissionNode,
)
from .core import (
    BytesData,
    BytesDataSource,
    DataSink,
    DataSource,
    EncryptedDataSource,
    FileDataSink,
    FileDataSource,
    FlowBuilder,
    submission_fee,
    submission_root,
)
from .evm import EvmClient
from .indexer import IndexerClient, IndexerDownloader
from .kv import CachedKvClient, KVBatcher, KvClient, KvIterator, StreamDataBuilder
from .node import ZgsKvClient, ZgsNodeClient
from .rpc import RpcClient, RpcError
from .transfer import (
    Downloader,
    DownloadNode,
    DownloadOption,
    EncryptionHeader,
    FinalityRequirement,
    NodeDownloader,
    NodeDownloaderConfig,
    NodeUploader,
    NodeUploaderConfig,
    Uploader,
    UploadOption,
    UploadResult,
    decrypt_file,
    decrypt_segment,
    encrypt_file,
)
from .types import (
    FileInfo,
    IPLocation,
    KeyValue,
    SegmentWithProof,
    ShardConfig,
    ShardedNode,
    ShardedNodes,
    Transaction,
    Value,
)

_TRACE_LEVEL = 5
if not hasattr(logging, "TRACE"):
    logging.addLevelName(_TRACE_LEVEL, "TRACE")

    def _trace(  # type: ignore[name-defined]
        self: logging.Logger, message: str, *args, **kwargs
    ) -> None:
        """Log a TRACE-level message on a logger instance."""
        if self.isEnabledFor(_TRACE_LEVEL):
            self._log(_TRACE_LEVEL, message, args, **kwargs)  # pylint: disable=protected-access

    logging.Logger.trace = _trace  # type: ignore[attr-defined]

_logger = logging.getLogger("zg_storage")
_logger.propagate = True
if not _logger.handlers:
    _logger.addHandler(logging.NullHandler())


def configure_logging(spec: str) -> None:
    """
    Configure logging levels from a spec string like:
    "debug,hyper=info,h2=info,rpc=info,discv5=info"
    The first token without '=' sets the root level.
    """
    if not spec:
        return
    if not logging.getLogger().handlers:
        logging.basicConfig(level=logging.INFO)
    level_map = {
        "trace": _TRACE_LEVEL,
        "debug": logging.DEBUG,
        "info": logging.INFO,
        "warn": logging.WARNING,
        "warning": logging.WARNING,
        "error": logging.ERROR,
        "critical": logging.CRITICAL,
        "fatal": logging.CRITICAL,
    }

    tokens = [t.strip() for t in spec.split(",") if t.strip()]
    default_level = None
    for token in tokens:
        if "=" not in token:
            default_level = token.lower()
            break
    if default_level:
        level = level_map.get(default_level)
        if level is not None:
            logging.getLogger().setLevel(level)

    for token in tokens:
        if "=" not in token:
            continue
        name, level_name = token.split("=", 1)
        name = name.strip()
        level_name = level_name.strip().lower()
        level = level_map.get(level_name)
        if not name or level is None:
            continue
        logging.getLogger(name).setLevel(level)


__all__ = [
    "RpcClient",
    "RpcError",
    "IndexerClient",
    "ZgsNodeClient",
    "ZgsKvClient",
    "EvmClient",
    "UploadOption",
    "DownloadOption",
    "FinalityRequirement",
    "UploadResult",
    "Uploader",
    "Downloader",
    "DownloadNode",
    "IndexerDownloader",
    "NodeUploader",
    "NodeUploaderConfig",
    "NodeDownloader",
    "NodeDownloaderConfig",
    "DataSink",
    "DataSource",
    "BytesData",
    "BytesDataSource",
    "FileDataSink",
    "FileDataSource",
    "EncryptedDataSource",
    "EncryptionHeader",
    "encrypt_file",
    "decrypt_file",
    "decrypt_segment",
    "KVBatcher",
    "CachedKvClient",
    "KvClient",
    "KvIterator",
    "StreamDataBuilder",
    "Submission",
    "SubmissionData",
    "SubmissionNode",
    "FlowBuilder",
    "submission_root",
    "submission_fee",
    "MarketContractClient",
    "FlowContractClient",
    "FileInfo",
    "IPLocation",
    "KeyValue",
    "SegmentWithProof",
    "ShardConfig",
    "ShardedNode",
    "ShardedNodes",
    "Transaction",
    "Value",
]
