"""OCR 与图像识别 Mixin"""

from __future__ import annotations

import time
from typing import TYPE_CHECKING, List, Optional, Tuple

from ..types import OcrResult

if TYPE_CHECKING:
    from ..device import Device


class OcrMixin:
    """OCR 与图像识别"""

    _client: ...

    def ocr(self, image: Optional[str] = None, x: Optional[float] = None, y: Optional[float] = None, 
            w: Optional[float] = None, h: Optional[float] = None, use_gpu: bool = False) -> List[OcrResult]:
        """屏幕 或 图片 OCR 识别
        
        Args:
            image: 图片路径, None 则截屏识别
            x, y, w, h: 识别区域 (0-1 相对坐标 或 像素坐标)
            use_gpu: 是否使用 GPU 加速 (手机端支持)
            
        Returns:
            OCR 结果列表
        """
        params = {
            "image": image,
            "x": x,
            "y": y,
            "w": w,
            "h": h,
            "use_gpu": use_gpu
        }
        result = self._client.auto_api("/ocr", params)
        return self._parse_ocr_result(result)

    def screen_ocr_x(self, specific_texts: Optional[List[str]] = None, x: Optional[float] = None, 
                     y: Optional[float] = None, w: Optional[float] = None, h: Optional[float] = None, 
                     use_gpu: bool = False) -> List[OcrResult]:
        """高级找字 — 返回匹配指定文字的结果 (支持正则)"""
        results = self.ocr(x=x, y=y, w=w, h=h, use_gpu=use_gpu)
        if not specific_texts:
            return results
        
        import re
        matched = []
        for r in results:
            for text in specific_texts:
                if re.search(text, r.text):
                    matched.append(r)
                    break
        return matched

    def screen_ocr_first_x(self, specific_texts: Optional[List[str]] = None, x: Optional[float] = None, 
                           y: Optional[float] = None, w: Optional[float] = None, h: Optional[float] = None, 
                           use_gpu: bool = False) -> Optional[OcrResult]:
        """高级找字 — 仅返回第一个匹配结果"""
        res = self.screen_ocr_x(specific_texts, x, y, w, h, use_gpu)
        return res[0] if res else None

    def image_ocr(self, path: str) -> List[OcrResult]:
        """对设备上的图片文件进行 OCR 识别"""
        return self.ocr(image=path)

    def _parse_ocr_result(self, result) -> List[OcrResult]:
        """解析 OCR 结果（统一处理 list 或 JSON 字符串格式）"""
        items: List[OcrResult] = []
        if isinstance(result, list):
            data = result
        elif isinstance(result, str):
            import json
            try:
                data = json.loads(result)
                if not isinstance(data, list):
                    return items
            except (ValueError, TypeError):
                return items
        else:
            return items

        for item in data:
            if isinstance(item, dict):
                bounds = item.get("bounds", item.get("rect", {}))
                if isinstance(bounds, dict):
                    b = (
                        int(bounds.get("left", bounds.get("x", 0))),
                        int(bounds.get("top", bounds.get("y", 0))),
                        int(bounds.get("right", bounds.get("x", 0) + bounds.get("width", 0))),
                        int(bounds.get("bottom", bounds.get("y", 0) + bounds.get("height", 0))),
                    )
                elif isinstance(bounds, (list, tuple)) and len(bounds) == 4:
                    b = tuple(int(x) for x in bounds)  # type: ignore
                else:
                    b = (0, 0, 0, 0)

                items.append(OcrResult(
                    text=item.get("text", ""),
                    confidence=float(item.get("confidence", item.get("score", 0))),
                    bounds=b,  # type: ignore
                ))
        return items

    def ocr_find(self, text: str, x: Optional[float] = None, y: Optional[float] = None, 
                 w: Optional[float] = None, h: Optional[float] = None, use_gpu: bool = False) -> Optional[OcrResult]:
        """查找屏幕上的文字
        
        Args:
            text: 要查找的文字 (正则)
            x, y, w, h: 搜索区域
        """
        import re
        results = self.ocr(x=x, y=y, w=w, h=h, use_gpu=use_gpu)
        for r in results:
            if re.search(text, r.text):
                return r
        return None

    def ocr_click(self, text: str, timeout: float = 10, x: Optional[float] = None, 
                  y: Optional[float] = None, w: Optional[float] = None, h: Optional[float] = None, 
                  use_gpu: bool = False) -> bool:
        """OCR 查找文字并点击"""
        deadline = time.time() + timeout
        while time.time() < deadline:
            result = self.ocr_find(text, x=x, y=y, w=w, h=h, use_gpu=use_gpu)
            if result:
                cx, cy = result.center
                self.click(cx, cy)  # type: ignore
                return True
            time.sleep(0.5)
        return False

    def ocr_wait(self, text: str, timeout: float = 10, x: Optional[float] = None, 
                 y: Optional[float] = None, w: Optional[float] = None, h: Optional[float] = None, 
                 use_gpu: bool = False) -> bool:
        """等待屏幕上出现指定文字"""
        deadline = time.time() + timeout
        while time.time() < deadline:
            if self.ocr_find(text, x=x, y=y, w=w, h=h, use_gpu=use_gpu):
                return True
            time.sleep(0.5)
        return False

    def ocr_exists_all(self, *texts: str, x: Optional[float] = None, y: Optional[float] = None, 
                       w: Optional[float] = None, h: Optional[float] = None, use_gpu: bool = False) -> bool:
        """判断所有文字是否都存在"""
        results = self.ocr(x=x, y=y, w=w, h=h, use_gpu=use_gpu)
        all_text = " ".join([r.text for r in results])
        import re
        for t in texts:
            if not re.search(t, all_text):
                return False
        return True

    def ocr_click_if_found(self, *texts: str, x: Optional[float] = None, y: Optional[float] = None, 
                           w: Optional[float] = None, h: Optional[float] = None, use_gpu: bool = False) -> bool:
        """如果所有文字都存在, 点击最后一个文字"""
        if not texts: return False
        results = self.ocr(x=x, y=y, w=w, h=h, use_gpu=use_gpu)
        
        import re
        found_last = None
        for t in texts:
            found = False
            for r in results:
                if re.search(t, r.text):
                    found = True
                    found_last = r
                    break
            if not found:
                return False
        
        if found_last:
            self.click(*found_last.center) # type: ignore
            return True
        return False

    def wait_for_text(self, *texts: str, timeout: float = 10, x: Optional[float] = None, 
                      y: Optional[float] = None, w: Optional[float] = None, h: Optional[float] = None, 
                      use_gpu: bool = False) -> bool:
        """等待屏幕上出现指定文字 (ocr_wait 的别名)"""
        return self.ocr_wait(*texts, timeout=timeout, x=x, y=y, w=w, h=h, use_gpu=use_gpu) # type: ignore

    def wait_for_image(self, template: str, timeout: float = 10, interval: float = 1.0, 
                       threshold: float = 0.8) -> Optional[Tuple[int, int]]:
        """等待屏幕出现指定图片"""
        deadline = time.time() + timeout
        while time.time() < deadline:
            res = self.find_image(template, threshold=threshold)
            if res:
                return res
            time.sleep(interval)
        return None

    def find_image(self, template: str, threshold: float = 0.8) -> Optional[Tuple[int, int]]:
        """模板匹配 — 在屏幕上查找图片

        Args:
            template: 模板图片路径（设备本地路径）；多个模板用 ; 分隔
            threshold: 匹配阈值 (0~1)

        Returns:
            匹配中心坐标 (x, y)，未找到返回 None
        """
        result = self._client.auto_api("/find_image", {
            "templates": template,
            "threshold": str(threshold),
        })
        if isinstance(result, dict):
            x = result.get("x")
            y = result.get("y")
            if x is not None and y is not None:
                return (int(x), int(y))
        # 解析字符串格式 "x,y,w,h,label,prob"
        if isinstance(result, str) and result:
            parts = result.split(",")
            if len(parts) >= 2:
                try:
                    return (int(float(parts[0])), int(float(parts[1])))
                except (ValueError, IndexError):
                    pass
        return None

    def pixel_color(self, x: int, y: int) -> Tuple[int, int, int]:
        """获取指定坐标的像素颜色

        Returns:
            (R, G, B) 元组，值范围 0-255
        """
        result = self._client.auto_api("/get_color", {"x": str(x), "y": str(y)})
        if isinstance(result, str) and result:
            parts = result.split(",")
            if len(parts) == 3:
                try:
                    return (int(parts[0]), int(parts[1]), int(parts[2]))
                except ValueError:
                    pass
        return (0, 0, 0)

    def color_at_points(self, points: List[Tuple[int, int]]) -> List[Tuple[int, int, int]]:
        """批量获取多个坐标点的像素颜色

        Args:
            points: 坐标点列表 [(x1,y1), (x2,y2), ...]

        Returns:
            对应的 RGB 颜色列表 [(r,g,b), ...]
        """
        points_str = " ".join(f"{x},{y}" for x, y in points)
        result = self._client.auto_api("/get_color", {"points": points_str})
        colors = []
        if isinstance(result, str) and result:
            for item in result.strip().split(" "):
                parts = item.split(",")
                if len(parts) == 3:
                    try:
                        colors.append((int(parts[0]), int(parts[1]), int(parts[2])))
                    except ValueError:
                        colors.append((0, 0, 0))
        return colors

    def find_color(self, rgb: str, points: str = "", threshold: int = 3, max_counts: int = 3) -> str:
        """多色找色

        Args:
            rgb: 主色 RGB 字符串，如 "255,0,0"
            points: 偏移点和颜色（换行分隔），与 ExportApi 格式相同
            threshold: 颜色容差
            max_counts: 最多返回数量

        Returns:
            找色结果字符串（与 ExportApi 原始格式相同）
        """
        result = self._client.auto_api("/find_color", {
            "rgb": rgb,
            "points": points,
            "prob": str(threshold),
            "max_counts": str(max_counts),
        })
        return str(result) if result else ""
