# -*- coding: utf-8 -*-
"""Excel 处理：读取 E 列（商品图片）从第 3 行起的图片，去文字后写回并保存。"""
import io
import zipfile
import shutil
import tempfile
import logging
from pathlib import Path
from typing import Callable, Optional, Set, Tuple

import openpyxl

from .image_text_remover import remove_text_from_image_bytes

logger = logging.getLogger(__name__)

COL_E_INDEX = 4
START_ROW_INDEX = 2


def _anchor_in_e_from_row3(anchor) -> bool:
    """判断图片是否在 E 列且从第 3 行开始（0-based row>=2）。"""
    if anchor is None:
        return False
    from_obj = getattr(anchor, "_from", None) or getattr(anchor, "from_obj", None)
    if from_obj is None:
        return False
    col = getattr(from_obj, "col", -1)
    row = getattr(from_obj, "row", -1)
    return col == COL_E_INDEX and row >= START_ROW_INDEX


def _get_e_column_media_paths(ws) -> Set[str]:
    """获取工作表中 E 列从第 3 行开始的所有图片在 xlsx 内的媒体路径（如 /xl/media/image1.jpeg）。"""
    paths = set()
    for img in getattr(ws, "_images", []):
        if not _anchor_in_e_from_row3(img.anchor):
            continue
        path = getattr(img, "path", None) or getattr(img, "ref", None)
        if path:
            # 统一为 zip 内路径格式（无前导 / 或带 xl/）
            path = path.lstrip("/").replace("\\", "/")
            if not path.startswith("xl/"):
                path = "xl/media/" + path.split("/")[-1] if "/" in path else "xl/media/" + path
            paths.add(path)
    return paths


def _normalize_zip_path(name: str) -> str:
    """xl/media/image1.jpeg 形式。"""
    name = name.replace("\\", "/").lstrip("/")
    if name.startswith("xl/media/"):
        return name
    if name.startswith("xl/"):
        return name
    return "xl/media/" + name.split("/")[-1] if "/" in name else "xl/media/" + name


def process_excel(
    input_path: str,
    output_dir: str,
    api_base_url: Optional[str] = None,
    api_key: Optional[str] = None,
    progress_callback: Optional[Callable[[int, int, str], None]] = None,
) -> str:
    """
    处理上传的 Excel：E 列从第 3 行起的图片去文字，复制工作簿并保存到 output_dir。
    文件名：原文件名_0000.xlsx，重复写入时序号递增。
    返回最终保存的完整路径。
    """
    input_path = Path(input_path)
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    # 确定输出文件名：原文件名_0000.xlsx 且序号递增
    stem = input_path.stem
    suffix = input_path.suffix.lower()
    if suffix != ".xlsx":
        suffix = ".xlsx"
    existing = list(output_dir.glob(f"{stem}_*.xlsx"))
    max_num = -1
    for p in existing:
        try:
            num_part = p.stem.rsplit("_", 1)[-1]
            if len(num_part) == 4 and num_part.isdigit():
                max_num = max(max_num, int(num_part))
        except Exception:
            pass
    next_num = max_num + 1
    out_name = f"{stem}_{next_num:04d}{suffix}"
    out_path = output_dir / out_name

    def report(current: int, total: int, message: str = ""):
        if progress_callback:
            progress_callback(current, total, message)

    # 用 openpyxl 只读方式获取需要处理的媒体路径（不修改原文件）
    wb = openpyxl.load_workbook(input_path, keep_vba=False, read_only=False)
    ws = wb.active
    media_paths = _get_e_column_media_paths(ws)
    wb.close()

    total = len(media_paths)
    report(0, max(total, 1), "正在读取 Excel 中的图片…")

    # 从原始 xlsx 的 zip 中读取需要处理的图片并去文字
    processed: dict = {}
    with zipfile.ZipFile(input_path, "r") as zf:
        names = zf.namelist()
        norm_names = {n.replace("\\", "/"): n for n in names}
        for idx, rel_path in enumerate(sorted(media_paths)):
            rn = rel_path.replace("\\", "/")
            n = norm_names.get(rn) or (rn if rn in names else None)
            if not n:
                for k, v in norm_names.items():
                    if k == rn or k.endswith("/" + rn.split("/")[-1]):
                        n = v
                        break
            if not n:
                report(idx + 1, total, f"跳过未找到: {rel_path}")
                continue
            try:
                data = zf.read(n)
                ext = Path(n).suffix or ".png"
                new_data = remove_text_from_image_bytes(
                    data,
                    api_base_url=api_base_url,
                    api_key=api_key,
                    image_ext=ext,
                )
                processed[n] = new_data
            except Exception as e:
                logger.exception("处理图片 %s 失败: %s", n, e)
                processed[n] = zf.read(n)
            report(idx + 1, total, f"去文字处理 {idx + 1}/{total}")

    # 复制整个 xlsx（zip），替换处理过的媒体文件
    report(total, total, "正在写入新文档…")
    with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as tmp:
        tmp_path = tmp.name
    try:
        with zipfile.ZipFile(input_path, "r") as z_in:
            with zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as z_out:
                for name in z_in.namelist():
                    if name in processed:
                        z_out.writestr(name, processed[name])
                    else:
                        z_out.writestr(name, z_in.read(name))
        shutil.move(tmp_path, out_path)
    except Exception:
        Path(tmp_path).unlink(missing_ok=True)
        raise

    report(total, total, "完成")
    return str(out_path)
