from __future__ import annotations

from collections.abc import Iterator
from pathlib import Path

from openpyxl import load_workbook

from market_api.importer.mappings import SheetSpec
from market_api.importer.rows import row_to_record


def normalize_header(value: object) -> str:
    if value is None:
        return ""
    return "".join(str(value).strip().split())


def validate_header_row(headers: tuple[object, ...], spec: SheetSpec) -> None:
    problems: list[str] = []
    for column in spec.columns:
        actual = normalize_header(headers[column.excel_index]) if column.excel_index < len(headers) else ""
        expected = normalize_header(column.source_header)
        if actual != expected:
            problems.append(
                f"第 {column.excel_index + 1} 列期望 {column.source_header!r}，实际 {actual!r}"
            )
    if problems:
        preview = "；".join(problems[:5])
        extra = f"；另有 {len(problems) - 5} 个问题" if len(problems) > 5 else ""
        raise ValueError(f"{spec.sheet_name} 表头不匹配：{preview}{extra}")


def validate_monthly_workbook(path: str | Path, specs: tuple[SheetSpec, ...]) -> None:
    workbook = load_workbook(path, read_only=True, data_only=True)
    try:
        for spec in specs:
            if spec.sheet_name not in workbook.sheetnames:
                raise ValueError(f"Excel 中找不到 sheet：{spec.sheet_name}")
            worksheet = workbook[spec.sheet_name]
            rows = worksheet.iter_rows(values_only=True)
            try:
                headers = next(rows)
            except StopIteration as exc:
                raise ValueError(f"{spec.sheet_name} 是空 sheet") from exc
            validate_header_row(headers, spec)
    finally:
        workbook.close()


def iter_sheet_records(path: str | Path, spec: SheetSpec) -> Iterator[dict[str, object]]:
    workbook = load_workbook(path, read_only=True, data_only=True)
    try:
        if spec.sheet_name not in workbook.sheetnames:
            raise ValueError(f"Excel 中找不到 sheet：{spec.sheet_name}")
        worksheet = workbook[spec.sheet_name]
        rows = worksheet.iter_rows(values_only=True)
        try:
            headers = next(rows)
        except StopIteration:
            return
        validate_header_row(headers, spec)
        for source_row_number, row in enumerate(rows, start=2):
            if any(value not in (None, "") for value in row):
                yield row_to_record(row, spec, source_row_number)
    finally:
        workbook.close()
