# 메인 윈도우 — 1920x1080 전체화면, 다크 테마, 4탭 네비게이션
from PyQt5.QtWidgets import (
    QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QStackedWidget, QLabel, QSizePolicy,
)
from PyQt5.QtCore import Qt, QPoint, QRect, QElapsedTimer
from PyQt5.QtGui import QPainter, QPolygon, QColor, QFont

from gui.pages.settings_page import SettingsPage
from gui.pages.register_page import RegisterPage
from gui.pages.inspect_page import InspectPage
from gui.pages.retrain_page import RetrainPage
from ai.detector import Detector
from logic.pattern_matcher import PatternMatcher
from db.sql_client import SQLClient


_DOT_OK   = ("background:#22cc55; border-radius:7px;"
             "min-width:14px; max-width:14px; min-height:14px; max-height:14px;")
_DOT_FAIL = ("background:#cc2222; border-radius:7px;"
             "min-width:14px; max-width:14px; min-height:14px; max-height:14px;")


class ChevronTabButton(QPushButton):
    # 우측이 ">" 화살표 모양인 breadcrumb/stepper 스타일 탭 버튼
    CHEVRON_W = 26  # 화살표 뾰족한 부분 너비(px)

    COLOR_ACTIVE_BG = QColor("#0055cc")
    COLOR_ACTIVE_FG = QColor("#ffffff")
    COLOR_HOVER_BG  = QColor("#2e2e2e")
    COLOR_HOVER_FG  = QColor("#ffffff")
    COLOR_IDLE_BG   = QColor("#222222")
    COLOR_IDLE_FG   = QColor("#aaaaaa")

    def __init__(self, text: str, is_first: bool = False,
                 is_last: bool = False, parent=None):
        super().__init__(text, parent)
        self._is_first = is_first
        self._is_last = is_last
        self._active = False
        self._hover = False
        self.setMinimumHeight(60)
        self.setCursor(Qt.PointingHandCursor)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.setFlat(True)
        self.setAttribute(Qt.WA_Hover, True)

    def setActive(self, active: bool):
        self._active = active
        self.update()

    def enterEvent(self, event):
        self._hover = True
        self.update()
        super().enterEvent(event)

    def leaveEvent(self, event):
        self._hover = False
        self.update()
        super().leaveEvent(event)

    def paintEvent(self, event):
        if self._active:
            bg, fg = self.COLOR_ACTIVE_BG, self.COLOR_ACTIVE_FG
        elif self._hover:
            bg, fg = self.COLOR_HOVER_BG, self.COLOR_HOVER_FG
        else:
            bg, fg = self.COLOR_IDLE_BG, self.COLOR_IDLE_FG

        w, h = self.width(), self.height()
        cw = self.CHEVRON_W
        left_cw  = 0 if self._is_first else cw
        right_cw = 0 if self._is_last  else cw

        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)
        p.setPen(Qt.NoPen)
        p.setBrush(bg)

        # 시계방향: 좌상 → 우상 → (우측 ▶) → 우하 → 좌하 → (좌측 V)
        pts = [QPoint(0, 0)]
        if self._is_last:
            pts += [QPoint(w, 0), QPoint(w, h)]
        else:
            pts += [QPoint(w - cw, 0), QPoint(w, h // 2), QPoint(w - cw, h)]
        pts.append(QPoint(0, h))
        if not self._is_first:
            pts.append(QPoint(cw, h // 2))

        p.drawPolygon(QPolygon(pts))

        p.setPen(fg)
        font = QFont(self.font())
        font.setPointSize(18)
        font.setBold(self._active)
        p.setFont(font)
        text_rect = QRect(left_cw, 0, w - left_cw - right_cw, h)
        p.drawText(text_rect, Qt.AlignCenter, self.text())


class MainWindow(QMainWindow):
    def __init__(self, insight_cam, basler_cam, config: dict, plc_client=None):
        super().__init__()
        self.insight    = insight_cam
        self.basler     = basler_cam
        self.config     = config
        self.detector   = Detector()
        self.matcher    = PatternMatcher()
        self.matcher.load()   # 앱 시작 시 저장된 패턴 자동 로드
        self.db_client  = SQLClient()
        self.plc_client = plc_client

        self.setWindowTitle("리플렉터 검사 시스템")
        self.showFullScreen()

        # 재학습 탭 연속 클릭(창 최소화 단축) 감지용
        self._retrain_click_timer = QElapsedTimer()
        self._retrain_click_timer.start()

        self._build_ui()
        self._switch_tab(0)
        self._auto_connect_db()
        self.update_connection_status()

    # ================================================================== #
    # UI 구성
    # ================================================================== #

    def _build_ui(self):
        root = QWidget()
        self.setCentralWidget(root)
        layout = QVBoxLayout(root)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        layout.addWidget(self._build_tab_bar())
        layout.addWidget(self._build_stack(), stretch=1)
        layout.addWidget(self._build_status_bar())

    def _build_tab_bar(self) -> QWidget:
        bar = QWidget()
        bar.setFixedHeight(60)
        # 화살표 모양 사이의 빈 삼각형 영역에서 보일 배경
        bar.setStyleSheet("background:#1a1a1a;")
        row = QHBoxLayout(bar)
        row.setContentsMargins(0, 0, 0, 0)
        row.setSpacing(0)

        labels = ["환경설정", "제품 등록", "검사", "재학습"]
        self._tab_btns = []
        for i, label in enumerate(labels):
            btn = ChevronTabButton(
                label,
                is_first=(i == 0),
                is_last=(i == len(labels) - 1),
            )
            btn.clicked.connect(lambda _, idx=i: self._switch_tab(idx))
            self._tab_btns.append(btn)
            row.addWidget(btn)
        return bar

    def _build_stack(self) -> QStackedWidget:
        self._stack = QStackedWidget()

        # belt_delay = 거리 / 속도 (config 기본값 사용)
        _conv = self.config.get("conveyor", {})
        _dist  = _conv.get("distance_cm", 100.0)
        _speed = _conv.get("speed_cms",    30.0)
        _belt_delay = _dist / _speed if _speed > 0 else 3.33

        self._settings_page = SettingsPage(
            self.insight, self.basler, self.config,
            detector=self.detector,
            update_insight_cb=self.update_insight,
            update_basler_cb=self.update_basler,
            update_detector_cb=self.update_detector,
            update_db_cb=self.update_db,
            update_plc_cb=self.update_plc,
            plc_client=self.plc_client,
        )
        self._settings_page.cognex_status_changed.connect(
            lambda _: self.update_connection_status()
        )
        self._settings_page.basler_status_changed.connect(
            lambda _: self.update_connection_status()
        )
        self._settings_page.plc_status_changed.connect(
            lambda _: self.update_connection_status()
        )

        self._register_page = RegisterPage(
            self.insight, matcher=self.matcher,
            db_client=self.db_client, config=self.config,
        )
        self._inspect_page  = InspectPage(
            self.insight, self.basler,
            detector=self.detector,
            belt_delay=_belt_delay,
            db_client=self.db_client,
            config=self.config,
        )
        self._inspect_page.update_matcher(self.matcher)
        self._settings_page.belt_settings_changed.connect(
            self._inspect_page.update_belt_delay
        )

        self._pages = [
            self._settings_page,
            self._register_page,
            self._inspect_page,
            RetrainPage(),
        ]
        for page in self._pages:
            self._stack.addWidget(page)
        return self._stack

    def _build_status_bar(self) -> QWidget:
        bar = QWidget()
        bar.setFixedHeight(36)
        bar.setStyleSheet("background:#111111;")
        row = QHBoxLayout(bar)
        row.setContentsMargins(16, 0, 16, 0)
        row.setSpacing(20)

        self._dot_cognex = self._make_dot(self.insight.is_connected())
        self._dot_basler  = self._make_dot(
            self.basler.is_connected() if self.basler else False
        )
        self._dot_db      = self._make_dot(False)
        self._dot_plc     = self._make_dot(
            bool(self.plc_client and self.plc_client.is_connected())
        )

        self._lbl_cognex = QLabel("코그넥스")
        self._lbl_basler = QLabel("Basler")
        self._lbl_db     = QLabel("DB")
        self._lbl_plc    = QLabel("PLC")
        for lbl in (self._lbl_cognex, self._lbl_basler, self._lbl_db, self._lbl_plc):
            lbl.setStyleSheet("color:#aaaaaa; font-size:13px;")

        row.addWidget(self._dot_cognex)
        row.addWidget(self._lbl_cognex)
        row.addWidget(self._dot_basler)
        row.addWidget(self._lbl_basler)
        row.addWidget(self._dot_db)
        row.addWidget(self._lbl_db)
        row.addWidget(self._dot_plc)
        row.addWidget(self._lbl_plc)
        row.addStretch()
        return bar

    @staticmethod
    def _make_dot(connected: bool) -> QLabel:
        dot = QLabel()
        dot.setStyleSheet(_DOT_OK if connected else _DOT_FAIL)
        return dot

    # ================================================================== #
    # 탭 전환
    # ================================================================== #

    def _switch_tab(self, idx: int):
        # 재학습 탭(3)을 600ms 이내에 연속으로 두 번 클릭하면 창 최소화
        if idx == 3:
            if (self._stack.currentIndex() == 3
                    and self._retrain_click_timer.elapsed() < 600):
                self.showMinimized()
                self._retrain_click_timer.restart()
                return
            self._retrain_click_timer.restart()

        self._stack.setCurrentIndex(idx)
        for i, btn in enumerate(self._tab_btns):
            btn.setActive(i == idx)
        if idx == 0:
            self._settings_page._sync_connection_status()
        elif idx == 1:
            self._register_page.load_products()
        elif idx == 2:
            self._inspect_page.refresh_wk_results()
        self.update_connection_status()

    # ================================================================== #
    # 코그넥스 인스턴스 교체 (SettingsPage 연결 성공 시 호출)
    # ================================================================== #

    def update_insight(self, new_insight):
        self.insight = new_insight
        self._register_page._insight = new_insight
        self._inspect_page.update_insight(new_insight)

    def update_basler(self, new_basler):
        self.basler = new_basler
        self._inspect_page.update_basler(new_basler)

    def update_detector(self, new_detector):
        self.detector = new_detector
        if hasattr(self, "_inspect_page"):
            self._inspect_page.update_detector(new_detector)

    def update_db(self, db_client):
        self.db_client = db_client
        connected = db_client is not None and db_client.is_connected()
        if hasattr(self, "_register_page"):
            self._register_page.update_db(db_client)
        if hasattr(self, "_inspect_page"):
            self._inspect_page.update_db(db_client)
        if hasattr(self, "_settings_page"):
            self._settings_page._db_client = db_client
            self._settings_page._set_db_connected(connected)
        self.update_connection_status()

    def update_plc(self, plc_client):
        self.plc_client = plc_client
        connected = plc_client is not None and plc_client.is_connected()
        if hasattr(self, "_settings_page"):
            self._settings_page._plc_client = plc_client
            self._settings_page._set_plc_connected(connected)
        self.update_connection_status()

    def _auto_connect_db(self):
        """앱 시작 시 config.json DB 접속 정보로 자동 연결 시도."""
        db_cfg = self.config.get("db", {})
        server   = db_cfg.get("server", "").strip()
        database = db_cfg.get("database", "").strip()
        username = db_cfg.get("username", "").strip()
        password = db_cfg.get("password", "")
        if not server or not database:
            return
        ok = self.db_client.connect(server, database, username, password)
        if ok:
            self.update_db(self.db_client)

    # ================================================================== #
    # 실제 연결 상태를 읽어 상태바 전체 갱신
    # ================================================================== #

    def update_connection_status(self):
        cognex_ok = bool(self.insight and self.insight.is_connected())
        self._dot_cognex.setStyleSheet(_DOT_OK if cognex_ok else _DOT_FAIL)
        self._lbl_cognex.setText("코그넥스  연결됨" if cognex_ok else "코그넥스  연결 안됨")
        self._lbl_cognex.setStyleSheet(
            "color:#1D9E75; font-size:13px; font-weight:bold;" if cognex_ok
            else "color:#aaaaaa; font-size:13px;"
        )

        basler_ok = bool(self.basler and self.basler.is_connected())
        self._dot_basler.setStyleSheet(_DOT_OK if basler_ok else _DOT_FAIL)
        self._lbl_basler.setText("Basler  연결됨" if basler_ok else "Basler  연결 안됨")
        self._lbl_basler.setStyleSheet(
            "color:#1D9E75; font-size:13px; font-weight:bold;" if basler_ok
            else "color:#aaaaaa; font-size:13px;"
        )

        db_ok = bool(self.db_client and self.db_client.is_connected())
        self._dot_db.setStyleSheet(_DOT_OK if db_ok else _DOT_FAIL)
        self._lbl_db.setText("DB  연결됨" if db_ok else "DB  연결 안됨")
        self._lbl_db.setStyleSheet(
            "color:#1D9E75; font-size:13px; font-weight:bold;" if db_ok
            else "color:#aaaaaa; font-size:13px;"
        )

        plc_ok = bool(self.plc_client and self.plc_client.is_connected())
        self._dot_plc.setStyleSheet(_DOT_OK if plc_ok else _DOT_FAIL)
        self._lbl_plc.setText("PLC  연결됨" if plc_ok else "PLC  연결 안됨")
        self._lbl_plc.setStyleSheet(
            "color:#1D9E75; font-size:13px; font-weight:bold;" if plc_ok
            else "color:#aaaaaa; font-size:13px;"
        )

