"""
内存管理和性能优化工具
"""

import gc
import sys
import weakref
from contextlib import contextmanager
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Any, Callable, Iterator

from ..utils.exceptions import MemoryError


class MemoryStrategy(Enum):
    """内存管理策略"""

    STANDARD = "standard"
    STREAMING = "streaming"
    BATCHED = "batched"
    LAZY = "lazy"
    MEMORY_ONLY = "memory_only"


@dataclass
class MemoryConfig:
    """内存配置设置"""

    max_memory_usage_mb: int = 500
    batch_size: int = 1000
    streaming_chunk_size: int = 10000
    enable_compression: bool = True
    enable_caching: bool = True
    cache_size_mb: int = 100
    gc_threshold: int = 1000
    lazy_loading: bool = True


class MemoryManager:
    """
    内存管理工具，用于高效处理大型Excel文件
    """

    def __init__(
        self,
        config: MemoryConfig | None = None,
        strategy: MemoryStrategy | None = None,
    ) -> None:
        """
        初始化内存管理器

        参数:
            config: 内存配置设置
            strategy: 可选的初始内存策略
        """
        self.config = config or MemoryConfig()
        self._memory_usage = 0
        self._cache: dict[str, Any] = {}
        self._object_registry: list[weakref.ref[Any]] = []
        self._gc_counter = 0
        self._strategy = MemoryStrategy.STANDARD
        if strategy is not None:
            self.set_strategy(strategy)

    def set_strategy(self, strategy: MemoryStrategy) -> None:
        """
        设置内存管理策略

        参数:
            strategy: 要使用的内存策略
        """
        self._strategy = strategy

    @property
    def strategy(self) -> MemoryStrategy:
        """当前内存管理策略"""
        return self._strategy

    def get_memory_usage(self) -> int:
        """
        获取当前内存使用量（字节）

        返回:
            内存使用量（字节）
        """
        return self._memory_usage

    def get_memory_usage_mb(self) -> float:
        """
        获取当前内存使用量（MB）

        返回:
            内存使用量（MB）
        """
        return self._memory_usage / (1024 * 1024)

    def check_memory_limit(self) -> bool:
        """
        检查内存使用量是否在配置限制内

        返回:
            如果在限制内返回True，否则返回False
        """
        max_bytes = self.config.max_memory_usage_mb * 1024 * 1024
        return self._memory_usage <= max_bytes

    def allocate_memory(self, size: int) -> None:
        """
        分配内存并检查限制

        参数:
            size: 内存大小（字节）

        异常:
            MemoryError: 如果超出内存限制
        """
        self._memory_usage += size
        if not self.check_memory_limit():
            self._cleanup_memory()
            if not self.check_memory_limit():
                raise MemoryError(
                    f"内存限制已超出: {self.get_memory_usage_mb():.1f}MB > "
                    f"{self.config.max_memory_usage_mb}MB"
                )

    def deallocate_memory(self, size: int) -> None:
        """
        释放内存

        参数:
            size: 内存大小（字节）
        """
        self._memory_usage = max(0, self._memory_usage - size)

    def register_object(self, obj: Any) -> None:
        """
        注册对象以进行内存跟踪

        参数:
            obj: 要注册的对象
        """
        self._object_registry.append(weakref.ref(obj))

    def _cleanup_memory(self) -> None:
        """
        执行内存清理
        """
        # 清除无效的对象引用
        self._object_registry = [
            ref for ref in self._object_registry if ref() is not None
        ]

        # 如果启用了缓存则清除缓存
        if self.config.enable_caching:
            self._clear_cache()

        # 强制垃圾回收
        gc.collect()

        # 更新内存使用量
        self._memory_usage = self._estimate_memory_usage()

    def _clear_cache(self) -> None:
        """
        清除内存缓存
        """
        cache_size = sum(sys.getsizeof(v) for v in self._cache.values())
        max_cache_size = self.config.cache_size_mb * 1024 * 1024

        if cache_size > max_cache_size:
            # 移除最旧的缓存条目
            keys_to_remove = list(self._cache.keys())[: len(self._cache) // 2]
            for key in keys_to_remove:
                del self._cache[key]

    def _estimate_memory_usage(self) -> int:
        """
        估算当前内存使用量

        返回:
            估算的内存使用量（字节）
        """
        # 这是一个简化的估算
        # 在实际实现中，这会更加复杂
        total = 0

        # 计算活动对象
        for ref in self._object_registry:
            obj = ref()
            if obj is not None:
                total += sys.getsizeof(obj)

        # 计算缓存
        total += sum(sys.getsizeof(v) for v in self._cache.values())

        return total

    @contextmanager
    def memory_context(self, strategy: MemoryStrategy) -> Iterator[None]:
        """
        临时内存策略变更的上下文管理器

        参数:
            strategy: 临时内存策略
        """
        old_strategy = self._strategy
        self.set_strategy(strategy)
        try:
            yield
        finally:
            self.set_strategy(old_strategy)

    def process_in_batches(
        self, data: list[Any], processor: Callable[[list[Any]], list[Any]]
    ) -> list[Any]:
        """
        分批处理数据以管理内存使用

        参数:
            data: 要处理的数据
            processor: 处理函数

        返回:
            处理后的数据
        """
        if self._strategy != MemoryStrategy.BATCHED:
            return processor(data)

        results: list[Any] = []
        batch_size = self.config.batch_size

        for i in range(0, len(data), batch_size):
            batch = data[i : i + batch_size]
            batch_results = processor(batch)
            results.extend(batch_results)

            # 每批处理后清理
            self._gc_counter += 1
            if self._gc_counter >= self.config.gc_threshold:
                gc.collect()
                self._gc_counter = 0

        return results

    def stream_process(self, data_source: Any, processor: Callable[[Any], Any]) -> Any:
        """
        流式处理数据以最小化内存使用

        参数:
            data_source: 数据源
            processor: 处理函数

        返回:
            处理后的数据流
        """
        if self._strategy != MemoryStrategy.STREAMING:
            return processor(data_source)

        # 这是一个简化的流式实现
        # 在实际实现中，这会使用生成器和迭代器
        chunk_size = self.config.streaming_chunk_size

        if hasattr(data_source, "__iter__"):
            # 分块处理
            result_chunks: list[Any] = []
            chunk: list[Any] = []

            for item in data_source:
                chunk.append(item)

                if len(chunk) >= chunk_size:
                    processed_chunk = processor(chunk)
                    result_chunks.append(processed_chunk)
                    chunk = []

                    # 清理
                    if self._gc_counter >= self.config.gc_threshold:
                        gc.collect()
                        self._gc_counter = 0
                    self._gc_counter += 1

            # 处理剩余的块
            if chunk:
                processed_chunk = processor(chunk)
                result_chunks.append(processed_chunk)

            return result_chunks
        else:
            return processor(data_source)

    def lazy_load(self, file_path: str | Path) -> Any:
        """
        惰性加载文件以最小化内存使用

        参数:
            file_path: 文件路径

        返回:
            惰性加载的数据
        """
        if not self.config.lazy_loading:
            return self._load_full_file(file_path)

        # 返回一个惰性加载器对象
        return LazyFileLoader(file_path, self)

    def _load_full_file(self, file_path: str | Path) -> Any:
        """
        将整个文件加载到内存中

        参数:
            file_path: 文件路径

        返回:
            加载的数据
        """
        with open(file_path, "rb") as f:
            data = f.read()
            self.allocate_memory(len(data))
            return data

    def optimize_memory(self) -> dict[str, Any]:
        """
        执行全面的内存优化

        返回:
            优化统计信息
        """
        stats = {
            "before_mb": self.get_memory_usage_mb(),
            "objects_cleaned": 0,
            "cache_cleared": False,
            "gc_performed": False,
        }

        # 清理无效对象
        before_count = len(self._object_registry)
        self._object_registry = [
            ref for ref in self._object_registry if ref() is not None
        ]
        stats["objects_cleaned"] = before_count - len(self._object_registry)

        # 如果需要则清除缓存
        if self.config.enable_caching:
            cache_size = sum(sys.getsizeof(v) for v in self._cache.values())
            max_cache_size = self.config.cache_size_mb * 1024 * 1024

            if cache_size > max_cache_size:
                self._clear_cache()
                stats["cache_cleared"] = True

        # 执行垃圾回收
        gc.collect()
        stats["gc_performed"] = True

        # 更新内存使用量
        self._memory_usage = self._estimate_memory_usage()
        stats["after_mb"] = self.get_memory_usage_mb()

        return stats

    def get_registered_object_count(self) -> int:
        """
        获取跟踪的活动对象数量
        """
        self._object_registry = [
            ref for ref in self._object_registry if ref() is not None
        ]
        return len(self._object_registry)

    def get_cache_entry_count(self) -> int:
        """
        获取缓存条目数量
        """
        return len(self._cache)


class LazyFileLoader:
    """
    惰性文件加载器，用于内存高效的文件访问
    """

    def __init__(self, file_path: str | Path, memory_manager: MemoryManager) -> None:
        """
        初始化惰性文件加载器

        参数:
            file_path: 文件路径
            memory_manager: 内存管理器实例
        """
        self.file_path = Path(file_path)
        self.memory_manager = memory_manager
        self._loaded_data: bytes | None = None
        self._loaded_size: int = 0

    def load_chunk(self, offset: int, size: int) -> bytes:
        """
        加载文件的特定块

        参数:
            offset: 字节偏移量
            size: 块大小

        返回:
            文件块数据
        """
        with open(self.file_path, "rb") as f:
            f.seek(offset)
            data = f.read(size)
            self.memory_manager.allocate_memory(len(data))
            return data

    def load_full(self) -> bytes:
        """
        加载整个文件

        返回:
            文件数据
        """
        if self._loaded_data is not None:
            return self._loaded_data

        with open(self.file_path, "rb") as f:
            data = f.read()
            self._loaded_data = data
            self._loaded_size = len(data)
            self.memory_manager.allocate_memory(self._loaded_size)

        return self._loaded_data

    def unload(self) -> None:
        """
        从内存中卸载文件数据
        """
        if self._loaded_data is not None:
            self.memory_manager.deallocate_memory(self._loaded_size)
            self._loaded_data = None
            self._loaded_size = 0


def create_memory_optimized_workbook(
    file_path: str | Path | None = None,
    strategy: MemoryStrategy = MemoryStrategy.STANDARD,
    **kwargs: Any,
) -> Any:
    """
    创建内存优化的工作簿

    参数:
        file_path: 可选的文件路径
        strategy: 要使用的内存策略
        **kwargs: 额外配置

    返回:
        内存优化的工作簿
    """
    from ..core.workbook import Workbook

    # 创建内存管理器
    config = MemoryConfig(**kwargs)
    memory_manager = MemoryManager(config)
    memory_manager.set_strategy(strategy)

    # 使用内存管理器创建工作簿
    workbook = Workbook(file_path)
    workbook._memory_manager = memory_manager

    return workbook
