"""
matplotlib 기반 차트 위젯.

stats_view에서 주간/월간 추세를 시각화. matplotlib 미설치 시
ImportError 안내 라벨로 fallback.
"""
from typing import List, Tuple

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
from PyQt5.QtCore import Qt

from core.i18n import tr

try:
    import matplotlib
    from matplotlib.figure import Figure
    # frozen(main.exe) 빌드는 PyInstaller matplotlib hook이 'QtAgg'(backend_qtagg)만
    # 번들함 → backend_qt5agg import가 실패해 차트가 안 뜨던 문제.
    # 번들된 backend_qtagg를 우선 사용하고, 구버전(dev) 호환으로 qt5agg 폴백.
    try:
        from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
    except Exception:
        from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    matplotlib.rcParams['font.family'] = ['NanumSquare', 'Malgun Gothic', 'Apple SD Gothic Neo', 'sans-serif']
    matplotlib.rcParams['axes.unicode_minus'] = False
    _MPL = True
except Exception as _mpl_err:
    # ImportError 외 backend/sip 로딩 오류도 폴백 처리 + 실제 원인 기록(진단용)
    _MPL = False
    try:
        from utils.debug_log import dlog
        dlog(f"chart_widget: matplotlib unavailable: {type(_mpl_err).__name__}: {_mpl_err}")
    except Exception:
        pass


# 차트 색상 — 배경/그리드/텍스트는 현재 테마를 따름(_refresh_chart_colors),
# 막대/선은 데이터 구분용 고정 색.
_CHART_BG = '#25262B'
_CHART_GRID = '#2C2E33'
_CHART_TEXT = '#909296'
_CHART_BAR_NORMAL = '#4DABF7'  # accent blue
_CHART_BAR_OVERTIME = '#ff90b8'  # pink (데이터 구분용)
_CHART_BAR_WEEKEND = '#fcd34d'  # gold (데이터 구분용)
_CHART_AVG_LINE = '#51CF66'  # green


def _refresh_chart_colors() -> None:
    """배경/그리드/텍스트 색을 현재 앱 테마로 갱신 (라이트/다크 추종)."""
    global _CHART_BG, _CHART_GRID, _CHART_TEXT
    try:
        from ui.styles import ThemeColors
        _CHART_BG = ThemeColors.get('bg_secondary')
        _CHART_GRID = ThemeColors.get('border_subtle')
        _CHART_TEXT = ThemeColors.get('text_secondary')
    except Exception:
        pass


def _apply_dark_axes(ax) -> None:
    """차트 ax에 다크 테마 적용 — 텍스트, 그리드, spines, 배경."""
    ax.set_facecolor(_CHART_BG)
    ax.tick_params(axis='both', colors=_CHART_TEXT)
    ax.xaxis.label.set_color(_CHART_TEXT)
    ax.yaxis.label.set_color(_CHART_TEXT)
    ax.title.set_color(_CHART_TEXT)
    for spine in ax.spines.values():
        spine.set_color(_CHART_GRID)
    ax.grid(axis='y', alpha=0.25, color=_CHART_GRID)


def _apply_dark_figure(fig) -> None:
    """figure 배경을 현재 테마 톤으로 (모든 draw_* 진입점에서 호출됨)."""
    _refresh_chart_colors()
    fig.patch.set_facecolor(_CHART_BG)


class _Fallback(QWidget):
    """matplotlib 미설치 시 안내."""
    def __init__(self, message: str):
        super().__init__()
        layout = QVBoxLayout()
        label = QLabel(message)
        label.setAlignment(Qt.AlignCenter)
        label.setWordWrap(True)
        label.setStyleSheet("color: #909296; padding: 20px;")
        layout.addWidget(label)
        self.setLayout(layout)


def make_chart_widget(parent=None) -> QWidget:
    """차트가 그려질 빈 캔버스 위젯. matplotlib 없으면 fallback."""
    if not _MPL:
        return _Fallback(tr('chart.need_matplotlib'))
    _refresh_chart_colors()
    widget = QWidget(parent)
    widget.setStyleSheet(f"background: {_CHART_BG}; border-radius: 8px;")
    layout = QVBoxLayout()
    layout.setContentsMargins(0, 0, 0, 0)
    fig = Figure(figsize=(5, 3), dpi=100, tight_layout=True, facecolor=_CHART_BG)
    canvas = FigureCanvas(fig)
    canvas.setStyleSheet(f"background: {_CHART_BG};")
    layout.addWidget(canvas)
    widget.setLayout(layout)
    widget._figure = fig
    widget._canvas = canvas
    return widget


def draw_daily_hours(widget: QWidget, records: List[dict]) -> None:
    """일별 근무시간 막대 그래프 (호버 시 정확한 수치 툴팁)."""
    if not getattr(widget, '_figure', None):
        return
    fig = widget._figure
    fig.clear()
    _apply_dark_figure(fig)
    if not records:
        ax = fig.add_subplot(111)
        _apply_dark_axes(ax)
        ax.text(0.5, 0.5, tr('chart.no_records'), ha='center', va='center',
                  transform=ax.transAxes, color=_CHART_TEXT, fontsize=11)
        widget._canvas.draw()
        return

    dates = [r['date'][5:] for r in records]  # MM-DD만
    full_dates = [r['date'] for r in records]
    hours = [r.get('total_hours', 0) or 0 for r in records]
    overtimes = [(r.get('overtime_minutes', 0) or 0) / 60 for r in records]
    base = [max(h - o, 0) for h, o in zip(hours, overtimes)]

    ax = fig.add_subplot(111)
    bars_base = ax.bar(dates, base, label=tr('chart.label_normal'), color=_CHART_BAR_NORMAL)
    bars_ot = ax.bar(dates, overtimes, bottom=base, label=tr('chart.label_overtime'),
                       color=_CHART_BAR_OVERTIME)
    ax.set_ylabel(tr('chart.ylabel_hours'))
    legend = ax.legend(loc='upper left', fontsize=8, facecolor=_CHART_BG,
                          edgecolor=_CHART_GRID, labelcolor=_CHART_TEXT)
    ax.tick_params(axis='x', labelrotation=45, labelsize=8)
    _apply_dark_axes(ax)

    # 호버 annotation 설정
    annot = ax.annotate(
        "", xy=(0, 0), xytext=(15, 15),
        textcoords="offset points",
        bbox=dict(boxstyle="round,pad=0.4", fc="#1a1a26", ec=_CHART_BAR_NORMAL,
                    alpha=0.95),
        color="white", fontsize=9,
        arrowprops=dict(arrowstyle="->", color=_CHART_BAR_NORMAL),
    )
    annot.set_visible(False)

    def on_hover(event):
        if event.inaxes != ax:
            if annot.get_visible():
                annot.set_visible(False)
                widget._canvas.draw_idle()
            return
        for bars, kind in ((bars_base, 'base'), (bars_ot, 'ot')):
            for i, bar in enumerate(bars):
                if bar.contains(event)[0]:
                    h = hours[i]; ot = overtimes[i]
                    text = tr('chart.hover_text',
                                 date=full_dates[i], hours=f"{h:.1f}")
                    if ot > 0:
                        text += "\n" + tr('chart.hover_overtime', hours=f"{ot:.1f}")
                    annot.xy = (bar.get_x() + bar.get_width() / 2, bar.get_height() + bar.get_y())
                    annot.set_text(text)
                    annot.set_visible(True)
                    widget._canvas.draw_idle()
                    # 도전과제 #stat_chart_hover — 첫 발견 시 1회만 기록
                    db = getattr(widget, '_achievement_db', None)
                    if db is not None:
                        try:
                            if db.get_setting('chart_hover_discovered', 'false').lower() != 'true':
                                db.set_setting('chart_hover_discovered', 'true')
                        except Exception:
                            pass
                    return
        if annot.get_visible():
            annot.set_visible(False)
            widget._canvas.draw_idle()

    widget._canvas.mpl_connect("motion_notify_event", on_hover)
    widget._canvas.draw()


def draw_clock_in_distribution(widget: QWidget, records: List[dict]) -> None:
    """출근 시각 분포 히스토그램 (30분 빈)."""
    if not getattr(widget, '_figure', None):
        return
    fig = widget._figure
    fig.clear()
    _apply_dark_figure(fig)
    if not records:
        ax = fig.add_subplot(111)
        _apply_dark_axes(ax)
        ax.text(0.5, 0.5, tr('chart.no_records'), ha='center', va='center',
                  transform=ax.transAxes, color=_CHART_TEXT, fontsize=11)
        widget._canvas.draw()
        return

    minutes_list = []
    for r in records:
        ci = r.get('clock_in')
        if not ci:
            continue
        parts = ci.split(':')
        if len(parts) >= 2:
            try:
                minutes_list.append(int(parts[0]) * 60 + int(parts[1]))
            except ValueError:
                pass

    if not minutes_list:
        ax = fig.add_subplot(111)
        _apply_dark_axes(ax)
        ax.text(0.5, 0.5, tr('chart.no_records'), ha='center', va='center',
                  transform=ax.transAxes, color=_CHART_TEXT, fontsize=11)
        widget._canvas.draw()
        return

    bin_size = 30
    min_m = (min(minutes_list) // bin_size) * bin_size
    max_m = ((max(minutes_list) // bin_size) + 1) * bin_size
    bins = list(range(min_m, max_m + bin_size, bin_size))

    ax = fig.add_subplot(111)
    ax.hist(minutes_list, bins=bins, color=_CHART_BAR_NORMAL,
              edgecolor=_CHART_BG, linewidth=1)
    avg = sum(minutes_list) / len(minutes_list)
    avg_time = f"{int(avg//60):02d}:{int(avg%60):02d}"
    ax.axvline(avg, color=_CHART_AVG_LINE, linestyle='--', linewidth=2,
                label=tr('chart.avg_line', time=avg_time))
    ax.set_xticks([m for m in bins if m % 60 == 0])
    ax.set_xticklabels([f"{m//60:02d}:00" for m in bins if m % 60 == 0],
                       rotation=45, fontsize=8)
    ax.set_ylabel(tr('chart.ylabel_days'))
    legend = ax.legend(loc='upper right', fontsize=8, facecolor=_CHART_BG,
                          edgecolor=_CHART_GRID, labelcolor=_CHART_TEXT)
    _apply_dark_axes(ax)
    widget._canvas.draw()


def draw_weekday_avg(widget: QWidget, records: List[dict]) -> None:
    """요일별 평균 근무시간 막대 그래프."""
    if not getattr(widget, '_figure', None):
        return
    fig = widget._figure
    fig.clear()
    _apply_dark_figure(fig)

    from datetime import datetime as _dt
    weekday_totals = [0.0] * 7
    weekday_counts = [0] * 7
    for r in records:
        try:
            d = _dt.strptime(r['date'], '%Y-%m-%d')
        except (ValueError, TypeError):
            continue
        weekday_totals[d.weekday()] += r.get('total_hours', 0) or 0
        weekday_counts[d.weekday()] += 1

    avg = [(t / c) if c else 0 for t, c in zip(weekday_totals, weekday_counts)]
    labels = [tr('label.weekday_mon'), tr('label.weekday_tue'), tr('label.weekday_wed'),
              tr('label.weekday_thu'), tr('label.weekday_fri'), tr('label.weekday_sat'),
              tr('label.weekday_sun')]

    ax = fig.add_subplot(111)
    colors = [_CHART_BAR_NORMAL] * 5 + [_CHART_BAR_WEEKEND] * 2  # 주말 골드 강조
    ax.bar(labels, avg, color=colors)
    ax.set_ylabel(tr('chart.ylabel_avg_hours'))
    _apply_dark_axes(ax)
    widget._canvas.draw()
