"""
异步Excel处理模块，提供异步API接口支持并发处理。
"""

from __future__ import annotations

import asyncio
import concurrent.futures
from pathlib import Path
from typing import Any, Callable, Iterable, cast

from .core.workbook import Workbook as SymphraWorkbook
from .core.worksheet import Worksheet
from .utils.exceptions import ValidationError
from .utils.large_data_processor import DataFormat, LargeDataProcessor
from .utils.memory_manager import MemoryManager, MemoryStrategy

PathLike = str | Path
Executor = concurrent.futures.Executor


class _AsyncRunner:
    """小工具统一处理 to_thread / executor 调度。"""

    def __init__(
        self, executor: Executor | None = None, *, max_workers: int = 4
    ) -> None:
        self._own_executor = executor is None
        self._executor = executor or concurrent.futures.ThreadPoolExecutor(
            max_workers=max_workers
        )

    async def run(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
        loop = asyncio.get_running_loop()
        return await loop.run_in_executor(self._executor, lambda: func(*args, **kwargs))

    def shutdown(self) -> None:
        if self._own_executor and isinstance(
            self._executor, concurrent.futures.Executor
        ):
            self._executor.shutdown(wait=True)


class AsyncWorkbook:
    """异步工作簿包装器。"""

    def __init__(
        self,
        *,
        memory_manager: MemoryManager | None = None,
        executor: Executor | None = None,
        max_workers: int = 4,
    ) -> None:
        self._memory_manager = memory_manager or MemoryManager()
        self._runner = _AsyncRunner(executor, max_workers=max_workers)
        self._workbook: SymphraWorkbook | None = None

    async def load(self, file_path: PathLike | bytes) -> "AsyncWorkbook":
        """异步加载现有工作簿。"""

        def _load() -> SymphraWorkbook:
            if isinstance(file_path, bytes):
                return SymphraWorkbook.from_bytes(
                    file_path, memory_manager=self._memory_manager
                )
            else:
                return SymphraWorkbook.load(
                    file_path, memory_manager=self._memory_manager
                )

        self._workbook = await self._runner.run(_load)
        return self

    async def create(self, *, mode: str = "default") -> "AsyncWorkbook":
        """异步创建新工作簿。"""

        def _create() -> SymphraWorkbook:
            workbook = SymphraWorkbook(mode=mode, memory_manager=self._memory_manager)
            if mode != "write_only" and not workbook.sheetnames:
                workbook.create_sheet("Sheet1")
            return workbook

        self._workbook = await self._runner.run(_create)
        return self

    async def save(self, file_path: PathLike) -> None:
        """异步保存到文件。"""
        workbook = self._ensure_workbook()
        await self._runner.run(workbook.save, file_path)

    async def save_to_memory(self) -> bytes:
        """异步保存到内存。"""
        workbook = self._ensure_workbook()
        return cast(bytes, await self._runner.run(workbook.save_to_bytes))

    async def get_worksheet(self, name: str) -> AsyncWorksheet | None:
        """异步获取指定工作表。"""
        workbook = self._ensure_workbook()
        worksheet = await self._runner.run(workbook.get_sheet_by_name, name)
        if worksheet:
            return AsyncWorksheet(worksheet, executor=self._runner._executor)
        return None

    async def create_worksheet(self, name: str) -> AsyncWorksheet:
        """异步创建工作表。"""
        workbook = self._ensure_workbook()
        worksheet = await self._runner.run(workbook.create_worksheet, name)
        return AsyncWorksheet(worksheet, executor=self._runner._executor)

    async def delete_worksheet(self, name: str) -> bool:
        workbook = self._ensure_workbook()
        return cast(bool, await self._runner.run(workbook.delete_worksheet, name))

    async def get_sheet_names(self) -> list[str]:
        workbook = self._ensure_workbook()
        return cast(
            list[str], await self._runner.run(lambda: list(workbook.sheetnames))
        )

    @property
    def workbook(self) -> SymphraWorkbook | None:
        return self._workbook

    async def close(self) -> None:
        if self._workbook:
            await self._runner.run(self._workbook.close)
            self._workbook = None
        self._runner.shutdown()

    def _ensure_workbook(self) -> SymphraWorkbook:
        if self._workbook is None:
            raise ValidationError("工作簿未初始化，请先调用 create() 或 load()")
        return self._workbook


class AsyncWorksheet:
    """异步工作表包装器。"""

    def __init__(
        self,
        worksheet: Worksheet,
        *,
        executor: Executor | None = None,
        max_workers: int = 2,
    ) -> None:
        self._worksheet = worksheet
        self._runner = _AsyncRunner(executor, max_workers=max_workers)

    async def get_cell_value(self, cell_ref: str) -> Any:
        return await self._runner.run(self._worksheet.get_cell_value, cell_ref)

    async def set_cell_value(self, cell_ref: str, value: Any) -> None:
        await self._runner.run(self._worksheet.set_cell_value, cell_ref, value)

    async def get_range_values(self, range_ref: str) -> list[list[Any]]:
        return cast(
            list[list[Any]],
            await self._runner.run(self._worksheet.get_range_values, range_ref),
        )

    async def set_range_values(self, range_ref: str, values: list[list[Any]]) -> None:
        await self._runner.run(self._worksheet.set_range_values, range_ref, values)

    async def insert_rows(self, row_num: int, count: int = 1) -> None:
        await self._runner.run(self._worksheet.insert_rows, row_num, count)

    async def delete_rows(self, row_num: int, count: int = 1) -> None:
        await self._runner.run(self._worksheet.delete_rows, row_num, count)

    async def insert_columns(self, col_num: int, count: int = 1) -> None:
        await self._runner.run(self._worksheet.insert_columns, col_num, count)

    async def delete_columns(self, col_num: int, count: int = 1) -> None:
        await self._runner.run(self._worksheet.delete_columns, col_num, count)

    @property
    def worksheet(self) -> Worksheet:
        return self._worksheet

    async def close(self) -> None:
        self._runner.shutdown()


class AsyncBatchProcessor:
    """异步批处理器，用于处理多个文件或大数据集。"""

    def __init__(
        self,
        *,
        max_workers: int = 8,
        memory_manager: MemoryManager | None = None,
        executor: Executor | None = None,
    ) -> None:
        self._max_workers = max_workers
        self._runner = _AsyncRunner(executor, max_workers=max_workers)
        self._memory_manager = memory_manager or MemoryManager(
            strategy=MemoryStrategy.BATCHED
        )
        self._processor = LargeDataProcessor(memory_manager=self._memory_manager)

    async def process_multiple_files(
        self,
        file_paths: Iterable[PathLike],
        process_func: Callable[[SymphraWorkbook, Any], Any],
        *args: Any,
        **kwargs: Any,
    ) -> list[Any]:
        semaphore = asyncio.Semaphore(self._max_workers)
        results: list[Any] = []

        async def _handle(path: PathLike) -> Any:
            async with semaphore:

                def _task() -> Any:
                    workbook = SymphraWorkbook.load(path)
                    try:
                        return process_func(workbook, *args, **kwargs)
                    finally:
                        workbook.close()

                return await self._runner.run(_task)

        for coro in asyncio.as_completed([_handle(path) for path in file_paths]):
            results.append(await coro)
        return results

    async def process_large_dataset(
        self,
        data_iterator: Iterable[Any],
        output_path: PathLike,
        *,
        batch_size: int = 1000,
        memory_strategy: MemoryStrategy = MemoryStrategy.STREAMING,
        format_type: DataFormat | None = None,
        headers: list[str] | None = None,
    ) -> None:
        await self._runner.run(
            self._processor.export_large_dataset,
            iter(data_iterator),
            output_path,
            format_type=format_type or DataFormat.EXCEL,
            headers=headers,
            batch_size=batch_size,
            memory_strategy=memory_strategy,
        )

    async def close(self) -> None:
        self._runner.shutdown()


# 便捷函数
async def async_load_workbook(path: PathLike | bytes) -> AsyncWorkbook:
    workbook = AsyncWorkbook()
    return await workbook.load(path)


async def async_create_workbook(*, mode: str = "default") -> AsyncWorkbook:
    workbook = AsyncWorkbook()
    return await workbook.create(mode=mode)


async def async_process_files(
    file_paths: Iterable[PathLike],
    process_func: Callable[[SymphraWorkbook, Any], Any],
    *,
    max_workers: int = 8,
    memory_manager: MemoryManager | None = None,
    executor: Executor | None = None,
    **kwargs: Any,
) -> list[Any]:
    processor = AsyncBatchProcessor(
        max_workers=max_workers,
        memory_manager=memory_manager,
        executor=executor,
    )
    try:
        return await processor.process_multiple_files(
            file_paths, process_func, **kwargs
        )
    finally:
        await processor.close()
