"""
Worksheet类 - Symphra Excel库的核心组件
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Iterable, Iterator, Sequence, cast

from openpyxl.utils import get_column_letter
from openpyxl.worksheet.worksheet import Worksheet as OpenpyxlWorksheet

from ..styles.cell_style import CellStyle
from ..utils.exceptions import ValidationError, handle_validation_errors
from ..utils.helpers import (
    column_letter_to_number,
    column_number_to_letter,
    get_cell_range_bounds,
    validate_cell_reference,
)
from ..utils.memory_manager import MemoryManager

if TYPE_CHECKING:
    from ..images.excel_image import ExcelImage
    from ..images.image_processor import CellImageOptions


class Worksheet:
    """
    高性能工作表包装器，支持多种操作模式
    """

    def __init__(
        self,
        openpyxl_worksheet: OpenpyxlWorksheet,
        *,
        mode: str = "default",
        memory_manager: MemoryManager | None = None,
    ) -> None:
        """
        初始化工作表包装器

        参数:
            openpyxl_worksheet: 底层openpyxl工作表对象
            mode: 工作簿模式
            memory_manager: 可选的内存管理器，用于缓存报告
        """
        self._worksheet = openpyxl_worksheet
        self._name: str = openpyxl_worksheet.title
        self._mode = mode
        self._memory_manager = memory_manager
        self._cached_styles: dict[str, CellStyle] = {}
        self._image_helper: "ExcelImage" | None = None

        parent = getattr(openpyxl_worksheet, "parent", None)
        self._write_only = bool(
            mode == "write_only"
            or getattr(parent, "write_only", False)
            or getattr(openpyxl_worksheet, "write_only", False)
        )
        self._read_only = bool(
            mode == "read_only"
            or getattr(parent, "read_only", False)
            or getattr(openpyxl_worksheet, "read_only", False)
        )

    # ------------------------------------------------------------------ #
    # 基本元数据
    # ------------------------------------------------------------------ #
    @property
    def name(self) -> str:
        """获取工作表名称"""
        return self._name

    @name.setter
    def name(self, value: str) -> None:
        """设置工作表名称（只写模式下不允许）"""
        if self._write_only:
            raise ValidationError("只写模式下无法重命名工作表")
        self._worksheet.title = value
        self._name = value

    @property
    def max_row(self) -> int:
        """获取包含数据的最大行号"""
        value = getattr(self._worksheet, "max_row", 0)
        return int(value or 0)

    @property
    def max_column(self) -> int:
        """获取包含数据的最大列号"""
        value = getattr(self._worksheet, "max_column", 0)
        return int(value or 0)

    # ------------------------------------------------------------------ #
    # 单元格访问
    # ------------------------------------------------------------------ #
    def __getitem__(self, key: str) -> Any:
        return self.get_value(key)

    def __setitem__(self, key: str, value: Any) -> None:
        self.set_value(key, value)

    def get_value(self, cell_ref: str) -> Any:
        if self._write_only:
            raise ValidationError("只写工作表不支持随机单元格访问")

        if self._read_only:
            column, row = validate_cell_reference(cell_ref)
            col_num = column_letter_to_number(column)
            for row_data in self._worksheet.iter_rows(
                min_row=row,
                max_row=row,
                min_col=col_num,
                max_col=col_num,
                values_only=True,
            ):
                return row_data[0]
            return None

        cell = self._worksheet[cell_ref]
        return cell.value

    def get_cell_value(self, cell_ref: str) -> Any:
        return self.get_value(cell_ref)

    def set_cell_value(
        self,
        cell_ref: str,
        value: Any,
        style: CellStyle | None = None,
    ) -> None:
        self.set_value(cell_ref, value, style)

    @handle_validation_errors(error_message="设置单元格值失败")
    def set_value(
        self,
        cell_ref: str,
        value: Any,
        style: CellStyle | None = None,
    ) -> None:
        """
        设置单元格的值

        参数:
            cell_ref: 单元格引用 (如 'A1')
            value: 要设置的值
            style: 可选的单元格样式

        异常:
            ValidationError: 只读或只写模式下设置值时抛出
        """
        if self._read_only:
            raise ValidationError("只读模式下无法修改工作表")
        if self._write_only:
            raise ValidationError("只写工作表应使用append_row(s)方法而非随机赋值")

        cell = self._worksheet[cell_ref]
        cell.value = value
        if style:
            self.apply_style(cell_ref, style)

    # ------------------------------------------------------------------ #
    # 范围辅助方法
    # ------------------------------------------------------------------ #
    @handle_validation_errors(error_message="获取范围值失败")
    def get_range_values(self, range_ref: str) -> list[list[Any]]:
        """
        获取指定范围内的所有单元格值

        参数:
            range_ref: 范围引用 (如 'A1:B10')

        返回:
            二维列表,包含范围内所有单元格的值

        异常:
            ValidationError: 只写模式或范围无效时抛出
        """
        if self._write_only:
            raise ValidationError("只写工作表不保留单元格历史记录")

        (start_row, start_col), (end_row, end_col) = get_cell_range_bounds(range_ref)
        values: list[list[Any]] = []
        for row in self._worksheet.iter_rows(
            min_row=start_row,
            max_row=end_row,
            min_col=start_col,
            max_col=end_col,
            values_only=True,
        ):
            values.append(list(row))
        return values

    def set_range_values(self, start_cell: str, values: list[list[Any]]) -> None:
        if self._read_only:
            raise ValidationError("只读模式下无法修改工作表")
        if self._write_only:
            raise ValidationError(
                "只写工作表无法通过set_range_values写入，请改用append_rows方法"
            )

        start_col, start_row = validate_cell_reference(start_cell)
        start_col_num = column_letter_to_number(start_col)

        for row_offset, row_values in enumerate(values):
            for col_offset, value in enumerate(row_values):
                target_row = start_row + row_offset
                target_col = column_number_to_letter(start_col_num + col_offset)
                cell_ref = f"{target_col}{target_row}"
                self.set_value(cell_ref, value)

    # ------------------------------------------------------------------ #
    # 流式追加辅助方法
    # ------------------------------------------------------------------ #
    def append_row(self, row: Sequence[Any]) -> None:
        if self._read_only:
            raise ValidationError("只读模式下无法追加行")
        self._worksheet.append(list(row))

    def append_rows(self, rows: Iterable[Sequence[Any]]) -> None:
        for row in rows:
            self.append_row(row)

    # ------------------------------------------------------------------ #
    # 样式设置
    # ------------------------------------------------------------------ #
    @handle_validation_errors(error_message="应用单元格样式失败")
    def apply_style(self, cell_ref: str, style: CellStyle) -> None:
        """
        应用样式到指定单元格

        参数:
            cell_ref: 单元格引用 (如 'A1')
            style: 要应用的单元格样式

        异常:
            ValidationError: 只写模式或单元格引用无效时抛出
        """
        if self._write_only:
            raise ValidationError("只写工作表不支持单元格样式缓存")

        cell = self._worksheet[cell_ref]
        style.apply_to_cell(cell)
        if self._memory_manager and cell_ref not in self._cached_styles:
            self._memory_manager.allocate_memory(64)
        self._cached_styles[cell_ref] = style

    def apply_range_style(self, range_ref: str, style: CellStyle) -> None:
        if self._write_only:
            raise ValidationError("只写工作表不支持批量样式应用")

        (start_row, start_col), (end_row, end_col) = get_cell_range_bounds(range_ref)
        for row in range(start_row, end_row + 1):
            for col in range(start_col, end_col + 1):
                col_letter = column_number_to_letter(col)
                cell_ref = f"{col_letter}{row}"
                self.apply_style(cell_ref, style)

    # ------------------------------------------------------------------ #
    # 结构操作
    # ------------------------------------------------------------------ #
    def merge_cells(self, range_ref: str) -> None:
        if self._write_only:
            raise ValidationError("只写工作表不支持合并单元格")
        self._worksheet.merge_cells(range_ref)

    def unmerge_cells(self, range_ref: str) -> None:
        if self._write_only:
            raise ValidationError("只写工作表不支持拆分合并单元格")
        self._worksheet.unmerge_cells(range_ref)

    def insert_rows(self, row_idx: int, amount: int = 1) -> None:
        if self._write_only:
            raise ValidationError("只写工作表不支持插入行")
        if self._read_only:
            raise ValidationError("只读工作表不支持插入行")
        self._worksheet.insert_rows(row_idx, amount)

    def insert_cols(self, col_idx: int, amount: int = 1) -> None:
        if self._write_only or self._read_only:
            raise ValidationError("当前模式不支持插入列")
        self._worksheet.insert_cols(col_idx, amount)

    def delete_rows(self, row_idx: int, amount: int = 1) -> None:
        if self._write_only or self._read_only:
            raise ValidationError("当前模式不支持删除行")
        self._worksheet.delete_rows(row_idx, amount)

    def delete_cols(self, col_idx: int, amount: int = 1) -> None:
        if self._write_only or self._read_only:
            raise ValidationError("当前模式不支持删除列")
        self._worksheet.delete_cols(col_idx, amount)

    def insert_columns(self, col_idx: int, amount: int = 1) -> None:
        self.insert_cols(col_idx, amount)

    def delete_columns(self, col_idx: int, amount: int = 1) -> None:
        self.delete_cols(col_idx, amount)

    # ------------------------------------------------------------------ #
    # 格式化工具
    # ------------------------------------------------------------------ #
    def auto_fit_columns(
        self, start_col: int | None = None, end_col: int | None = None
    ) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法自动调整列宽")

        if start_col is None:
            start_col = 1
        if end_col is None:
            end_col = self.max_column

        for col in range(start_col, end_col + 1):
            column_letter = get_column_letter(col)
            max_length = 0
            for row in range(1, self.max_row + 1):
                cell_value = self._worksheet[f"{column_letter}{row}"].value
                if cell_value:
                    cell_str = str(cell_value)
                    max_length = max(max_length, len(cell_str))
            adjusted_width = min(max_length + 2, 50)
            if adjusted_width > 0:
                self._worksheet.column_dimensions[column_letter].width = adjusted_width

    def auto_fit_rows(
        self, start_row: int | None = None, end_row: int | None = None
    ) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法自动调整行高")

        if start_row is None:
            start_row = 1
        if end_row is None:
            end_row = self.max_row

        for row in range(start_row, end_row + 1):
            self._worksheet.row_dimensions[row].auto_size = True

    def clear_range(self, range_ref: str) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法清除范围")
        for row in self._worksheet[range_ref]:
            for cell in row:
                cell.value = None
                cell.style = "Normal"

    # ------------------------------------------------------------------ #
    # 图像辅助方法
    # ------------------------------------------------------------------ #
    def insert_image(
        self,
        image_source: Any,
        cell_reference: str,
        *,
        width: int | None = None,
        height: int | None = None,
        options: CellImageOptions | None = None,
    ) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法插入图片")

        helper = self._get_image_helper()
        helper.insert_image(
            worksheet=self,
            image_source=image_source,
            cell_reference=cell_reference,
            width=width,
            height=height,
            options=options,
        )

    def insert_image_with_size(
        self,
        image_source: Any,
        cell_reference: str,
        *,
        cell_width: int | None = None,
        cell_height: int | None = None,
        options: CellImageOptions | None = None,
    ) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法插入图片")

        helper = self._get_image_helper()
        helper.insert_image_with_size(
            worksheet=self,
            image_source=image_source,
            cell_reference=cell_reference,
            cell_width=cell_width,
            cell_height=cell_height,
            options=options,
        )

    def insert_images_batch(self, images_data: list[dict[str, Any]]) -> None:
        if self._write_only:
            raise ValidationError("只写工作表无法插入图片")

        helper = self._get_image_helper()
        helper.insert_images_batch(self, images_data)

    def insert_image_in_cell(
        self,
        image_source: Any,
        cell_reference: str,
        *,
        options: CellImageOptions | None = None,
    ) -> None:
        """
        将图像插入单元格但保持原始大小

        参数:
            image_source: 图像源
            cell_reference: 目标单元格
            options: 图像选项（用于锚定和定位）
        """
        if self._write_only:
            raise ValidationError("只写工作表无法插入图片")
        helper = self._get_image_helper()
        helper.insert_image_in_cell(
            worksheet=self,
            image_source=image_source,
            cell_reference=cell_reference,
            options=options,
        )

    def get_used_range(self) -> str:
        if self.max_row == 0 or self.max_column == 0:
            return "A1:A1"
        start_cell = "A1"
        end_col_letter = column_number_to_letter(self.max_column)
        end_cell = f"{end_col_letter}{self.max_row}"
        return f"{start_cell}:{end_cell}"

    # ------------------------------------------------------------------ #
    # 迭代器
    # ------------------------------------------------------------------ #
    def iter_rows(
        self,
        min_row: int | None = None,
        max_row: int | None = None,
        min_col: int | None = None,
        max_col: int | None = None,
        values_only: bool = False,
    ) -> Iterator[tuple[Any, ...]]:
        rows = self._worksheet.iter_rows(
            min_row=min_row,
            max_row=max_row,
            min_col=min_col,
            max_col=max_col,
            values_only=values_only,
        )
        return cast(Iterator[tuple[Any, ...]], rows)

    def iter_cols(
        self,
        min_row: int | None = None,
        max_row: int | None = None,
        min_col: int | None = None,
        max_col: int | None = None,
        values_only: bool = False,
    ) -> Iterator[tuple[Any, ...]]:
        cols = self._worksheet.iter_cols(
            min_row=min_row,
            max_row=max_row,
            min_col=min_col,
            max_col=max_col,
            values_only=values_only,
        )
        return cast(Iterator[tuple[Any, ...]], cols)

    # ------------------------------------------------------------------ #
    # 缓存辅助方法
    # ------------------------------------------------------------------ #
    def clear_cached_styles(self) -> None:
        """清空样式缓存并让内存管理器有机会回收"""
        if self._memory_manager and self._cached_styles:
            approx_size = len(self._cached_styles) * 64
            self._memory_manager.deallocate_memory(approx_size)
        self._cached_styles.clear()

    def _get_image_helper(self) -> "ExcelImage":
        if self._image_helper is None:
            from ..images.excel_image import ExcelImage

            self._image_helper = ExcelImage()
        return self._image_helper
