# 검사 판별 로직 — PatMax 결과 판독 + 모델 판별 + Pass/Fail 판정
import cv2
import numpy as np

from db.sql_client import SQLClient
from logic.products import model_display_label


class Inspector:

    def __init__(self):
        self._pattern_cells: dict = {}

    def set_pattern_cells(self, cells: dict):
        """DB 기반 PatMax 셀 매핑 (refresh_wk_results 시 갱신)."""
        self._pattern_cells = cells or {}

    # ── Python PatMax 매칭 (주 경로) ─────────────────────────────────── #

    def match_image(self, image_bytes: bytes, matcher: "PatternMatcher") -> dict:
        """
        FTP로 받은 이미지 바이트를 Python PatternMatcher로 매칭.
        반환 형식은 read_patmax_results와 동일하여 identify_model에서 그대로 사용.
        """
        if not image_bytes:
            return {}

        arr = np.frombuffer(image_bytes, dtype=np.uint8)
        img = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED)
        if img is None:
            return {}

        all_scores = matcher.match_all(img)
        results    = {}

        for pid, score in all_scores.items():
            info = matcher.get_product_info(pid)
            if info is None:
                continue
            results[f"PY_{pid}"] = {
                "matched": score >= matcher.score_threshold,
                "score":   score,
                "model":   info,
                "raw":     f"python_match={score:.1f}",
            }

        return results

    # ── Cognex GV 셀 방식 (fallback) ────────────────────────────────── #

    def read_patmax_results(self, insight) -> dict:
        """PatMax 결과 셀 조회 → #ERR이면 실패, 그 외 점수 파싱."""
        results = {}
        for cell, model_info in self._pattern_cells.items():
            try:
                insight._send(f"GV{cell}")
                code = insight._read_line()
                if code != "1":
                    results[cell] = {
                        "matched": False, "score": 0.0,
                        "model": model_info, "raw": ""
                    }
                    continue
                value = insight._read_line()
                if "#ERR" in value or value.strip() == "":
                    results[cell] = {
                        "matched": False, "score": 0.0,
                        "model": model_info, "raw": value
                    }
                else:
                    # "(736.1,742.0) -1.8 = 82.9" 형식에서 = 뒤 값 추출
                    try:
                        score = float(value.split("=")[-1].strip())
                    except Exception:
                        score = 0.0
                    results[cell] = {
                        "matched": True, "score": score,
                        "model": model_info, "raw": value
                    }
            except Exception as e:
                print(f"[PatMax] {cell} 읽기 오류: {e}")
                results[cell] = {
                    "matched": False, "score": 0.0,
                    "model": model_info, "raw": ""
                }
        return results

    # ── 공통: 모델 판별 + 판정 ──────────────────────────────────────── #

    def identify_model(self, results: dict,
                       allowed_model_ids: "list | None" = None,
                       allowed_article_ids: "set | None" = None) -> dict:
        """매칭된 패턴 중 점수가 가장 높은 것을 선택해 허용 여부 판별."""
        matched_patterns = [
            (cell, info) for cell, info in results.items()
            if info["matched"]
        ]

        if not matched_patterns:
            return {
                "matched": False, "in_allowed": False,
                "model": None, "score": 0.0,
                "cognex_pass": False, "status": "인식 불가"
            }

        _best_cell, best_info = max(matched_patterns, key=lambda x: x[1]["score"])
        model = best_info["model"]
        label = model_display_label(model)

        if allowed_article_ids is not None:
            in_allowed = (
                SQLClient._norm_id(model.get("article_id")) in allowed_article_ids
            )
        else:
            in_allowed = model["id"] in (allowed_model_ids or [])

        return {
            "matched":     True,
            "in_allowed":  in_allowed,
            "model":       model,
            "score":       best_info["score"],
            "cognex_pass": in_allowed,
            "status": (
                f"{label} ({best_info['score']:.1f}점)"
                if in_allowed
                else f"작업 대상 외: {label}"
            ),
        }

    def judge(self, cognex_pass: bool, basler_pass: bool) -> str:
        return "PASS" if cognex_pass and basler_pass else "FAIL"
