# -*- coding: utf-8 -*-
"""图片去文字：去除图中叠加文字，尽量保留商品身上的文字（基于 OpenCV，可选 AI）。"""
import io
import base64
import logging
from typing import Optional, Tuple

import cv2
import numpy as np
from PIL import Image

logger = logging.getLogger(__name__)

# E 列从第 3 行开始（0-based 行为 2）
COL_E_INDEX = 4
START_ROW_INDEX = 2


def _decode_image_bytes(data: bytes) -> np.ndarray:
    """将图片字节转为 BGR 数组。"""
    nparr = np.frombuffer(data, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    if img is None:
        pil_img = Image.open(io.BytesIO(data))
        img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
    return img


def _encode_image_bgr(img: np.ndarray, ext: str = ".png") -> bytes:
    """将 BGR 数组编码为字节。"""
    ext = ext.lower()
    if ext in (".jpg", ".jpeg"):
        _, buf = cv2.imencode(".jpg", img)
    else:
        _, buf = cv2.imencode(".png", img)
    return buf.tobytes()


def remove_text_opencv(img_bgr: np.ndarray) -> np.ndarray:
    """
    使用 OpenCV 检测并修复（涂掉）可能的叠加文字区域。
    通过高对比度区域 + 形态学得到 mask，再 inpaint。
    商品身上的小字可能也会被弱化，但叠加的大字会优先被去掉。
    """
    h, w = img_bgr.shape[:2]
    gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

    # 二值化得到可能文字区域（黑字/白字都考虑）
    _, th1 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    th2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
    # 取边缘
    edges = cv2.Canny(gray, 50, 150)
    # 组合：文字往往是高对比度小块
    mask = np.zeros_like(gray, dtype=np.uint8)
    mask[(th1 != th2) | (edges > 0)] = 255
    # 形态学：膨胀成块，避免只涂细线
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    mask = cv2.dilate(mask, kernel)
    kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    mask = cv2.dilate(mask, kernel2)
    # 去掉过大的连通域（可能是商品主体）
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    area_thresh = (h * w) * 0.05
    mask_final = np.zeros_like(gray, dtype=np.uint8)
    for c in contours:
        if cv2.contourArea(c) < area_thresh:
            cv2.drawContours(mask_final, [c], -1, 255, -1)
    if mask_final.max() == 0:
        return img_bgr
    inpaint_radius = max(3, min(h, w) // 100)
    result = cv2.inpaint(img_bgr, mask_final, inpaint_radius, cv2.INPAINT_TELEA)
    return result


def remove_text_from_image_bytes(
    data: bytes,
    api_base_url: Optional[str] = None,
    api_key: Optional[str] = None,
    image_ext: str = ".png",
) -> bytes:
    """
    对图片字节做去文字处理。
    若提供了 api_base_url 与 api_key，可在此处调用支持图像编辑的大模型（当前未实现具体 API，仍用 OpenCV）。
    否则使用 OpenCV 进行去文字。
    """
    img = _decode_image_bytes(data)
    if img is None:
        return data
    # 若后续接入可返回编辑后图片的 AI 接口，可在此调用
    if api_base_url and api_key:
        try:
            out = _try_ai_remove_text(img, data, api_base_url, api_key, image_ext)
            if out is not None:
                return out
        except Exception as e:
            logger.warning("AI 去文字失败，回退 OpenCV: %s", e)
    out_bgr = remove_text_opencv(img)
    return _encode_image_bgr(out_bgr, image_ext)


def _try_ai_remove_text(
    img_bgr: np.ndarray,
    original_bytes: bytes,
    api_base_url: str,
    api_key: str,
    image_ext: str,
) -> Optional[bytes]:
    """
    尝试用兼容 OpenAI 的 vision/chat 接口做“去叠加文字”的说明；
    若接口支持图像编辑并返回图片，可在此实现。目前返回 None 表示不使用 AI 结果。
    """
    # 多数 chat/vision 接口只返回文本，不返回编辑后的图片，此处保留扩展点
    return None
