"""Telegram notifier for 골디(budget) — 후잉 동기화 실패 알림 전송.

openclaw.json 의 channels.telegram.accounts.budget.botToken 과 allowFrom[0] (관리자 chat_id)
를 사용해 직접 sendMessage 호출. 외부 의존성 없음.
"""
import json
import re
import urllib.parse
import urllib.request
from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo

CONFIG_PATH = Path("/Users/snowoyh/.openclaw/openclaw.json")
KST = ZoneInfo("Asia/Seoul")


def _load_budget_account():
    cfg = json.loads(CONFIG_PATH.read_text())
    acct = cfg["channels"]["telegram"]["accounts"]["budget"]
    token = acct["botToken"]
    chat_ids = acct.get("allowFrom") or []
    return token, chat_ids


def send(text: str, parse_mode: str = "HTML") -> bool:
    """관리자에게 텔레그램 메시지 전송. 성공 시 True. 실패해도 예외 안 던짐 (알림 자체로 흐름 막지 않음)."""
    try:
        token, chat_ids = _load_budget_account()
    except Exception as e:
        print(f"⚠️  notify: config 로드 실패: {e}")
        return False
    if not chat_ids:
        print("⚠️  notify: allowFrom 비어 있어 전송 대상 없음")
        return False

    ok = True
    url = f"https://api.telegram.org/bot{token}/sendMessage"
    for chat_id in chat_ids:
        payload = {
            "chat_id": chat_id,
            "text": text[:4000],
            "parse_mode": parse_mode,
            "disable_web_page_preview": "true",
        }
        data = urllib.parse.urlencode(payload).encode()
        req = urllib.request.Request(url, data=data, method="POST")
        try:
            with urllib.request.urlopen(req, timeout=10) as r:
                body = r.read().decode("utf-8", errors="replace")
                if r.status != 200:
                    print(f"⚠️  notify: telegram {r.status}: {body[:200]}")
                    ok = False
        except Exception as e:
            print(f"⚠️  notify: telegram 전송 실패: {e}")
            ok = False
    return ok


def escape_html(s: str) -> str:
    return (s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"))


def format_kst(iso: str) -> str:
    """imsg created_at(UTC ISO) -> 'MM-DD HH:MM' KST. 파싱 실패 시 원문."""
    if not iso:
        return ""
    try:
        dt = datetime.fromisoformat(iso.replace("Z", "+00:00")).astimezone(KST)
        return dt.strftime("%m-%d %H:%M")
    except Exception:
        return iso[:16]


def clean_reason(body: str, status: int) -> str:
    """후잉 응답 본문 -> 한국어 한 줄 사유. 모르는 패턴은 원문 그대로."""
    body = (body or "").strip()
    if status == 0:
        return f"네트워크 오류 — {body[:200]}"
    if not (200 <= status < 300):
        return f"HTTP {status} — {body[:200]}"
    if body.lower() == "fail":
        return "후잉이 형식 거절함 (사유 미제공). 보통 memo 누락 또는 인코딩 문제."

    # "Error :" / "Error:" 접두어 제거
    m = re.match(r"^Error\s*:?\s*(.+)$", body, flags=re.S)
    inner = (m.group(1).strip() if m else body).strip()

    # 알려진 패턴 → 한국어 번역
    # 1) "left/right account does not exist at entry_date. ... [계정명]"
    m = re.search(r"(left|right)\s+account\s+does\s+not\s+exist.*?\[(.+?)\]", inner, flags=re.I | re.S)
    if m:
        side = "차변" if m.group(1).lower() == "left" else "대변"
        name = m.group(2).strip()
        return f"{side} 계정 ‘{name}’ 이(가) 후잉 차트에 없습니다. 계정명 오타이거나 거래일에 닫혀있는 계정입니다."

    # 2) "[필드명] 필드가 없습니다"
    m = re.search(r"\[(\w+)\]\s*필드가\s*없습니다", inner)
    if m:
        return f"필수 필드 ‘{m.group(1)}’ 이(가) 빠졌습니다."

    # 3) entry_date 관련
    if re.search(r"entry_date.*(format|invalid|올바)", inner, flags=re.I):
        return "거래일(entry_date) 형식 오류. YYYYMMDD 8자리여야 합니다."

    # 4) money 관련
    if re.search(r"money.*(invalid|format|숫자|negative)", inner, flags=re.I):
        return "금액(money) 값이 잘못됐습니다. 양의 정수만 허용됩니다."

    # 5) section / webhook URL 만료
    if re.search(r"section|webhook|invalid\s*url|expired", inner, flags=re.I):
        return f"웹훅/섹션 문제 — {inner[:200]}"

    # 알려진 패턴 없음: 원문 (영문 그대로)
    return inner[:300]
