from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any


class UnsupportedWorkbookError(RuntimeError):
    pass


@dataclass(frozen=True)
class RawSheet:
    name: str
    rows: tuple[tuple[Any, ...], ...]


def read_workbook(path: Path) -> tuple[RawSheet, ...]:
    suffix = path.suffix.lower()
    if suffix == ".xlsx":
        return _read_xlsx(path)
    if suffix == ".xls":
        return _read_xls(path)
    raise UnsupportedWorkbookError(f"Unsupported workbook type: {suffix}")


def _read_xlsx(path: Path) -> tuple[RawSheet, ...]:
    try:
        from openpyxl import load_workbook
    except ImportError as exc:
        raise UnsupportedWorkbookError(
            "Reading .xlsx files requires openpyxl. Install requirements.txt."
        ) from exc

    workbook = load_workbook(path, read_only=True, data_only=True)
    try:
        return tuple(
            RawSheet(
                name=worksheet.title,
                rows=tuple(tuple(row) for row in worksheet.iter_rows(values_only=True)),
            )
            for worksheet in workbook.worksheets
        )
    finally:
        workbook.close()


def _read_xls(path: Path) -> tuple[RawSheet, ...]:
    try:
        import xlrd
    except ImportError as exc:
        raise UnsupportedWorkbookError(
            "Reading .xls files requires xlrd. Install requirements.txt."
        ) from exc

    workbook = xlrd.open_workbook(path, on_demand=True)
    sheets: list[RawSheet] = []
    try:
        for sheet_name in workbook.sheet_names():
            worksheet = workbook.sheet_by_name(sheet_name)
            rows: list[tuple[Any, ...]] = []
            for row_index in range(worksheet.nrows):
                values: list[Any] = []
                for column_index in range(worksheet.ncols):
                    cell = worksheet.cell(row_index, column_index)
                    value = cell.value
                    if cell.ctype == xlrd.XL_CELL_DATE:
                        value = xlrd.xldate_as_datetime(value, workbook.datemode)
                    values.append(value)
                rows.append(tuple(values))
            sheets.append(RawSheet(name=sheet_name, rows=tuple(rows)))
    finally:
        workbook.release_resources()
    return tuple(sheets)
