#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 유가 급변 감시. BYBIT:CLUSDT.P 를 TradingView 스캐너로 5분마다 조회.
# 이란 타격 실행 여부는 뉴스보다 유가가 먼저 반응한다.
import json, os, re, urllib.request, urllib.parse, datetime as dt

BASE      = os.path.expanduser("~/Claude/Projects/에이전트구축")
STATE_F   = os.path.join(BASE, "oil_watch_state.json")
LOG_F     = os.path.join(BASE, "oil_watch.log")
NQ_LEVELS = os.path.join(BASE, "nq_levels.py")

TICKER   = "BYBIT:CLUSDT.P"
CHAT_ID  = None
UP_5M    = 1.0     # 5분 급등 %
DN_5M    = -1.0    # 5분 급락 %
LEVELS   = [(86.75, "브렌트 90 환산"), (84.00, "하방 이탈"), (90.00, "WTI 90")]
COOLDOWN_MIN = 30
MIN_GAP, MAX_GAP = 180, 900

def log(m):
    ts = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
    line = "[%s] %s" % (ts, m)
    print(line)
    try:
        open(LOG_F, "a", encoding="utf-8").write(line + "\n")
    except Exception:
        pass

def secrets():
    s = open(NQ_LEVELS, encoding="utf-8").read()
    t = re.search(r'BOT_TOKEN\s*=\s*["\']([^"\']+)["\']', s)
    c = re.search(r'CHAT_ID\s*=\s*["\']?(-?\d+)["\']?', s)
    if not t: raise RuntimeError("BOT_TOKEN 못 찾음")
    return t.group(1), (CHAT_ID or (c.group(1) if c else None))

def telegram(text):
    tok, chat = secrets()
    d = urllib.parse.urlencode({"chat_id": chat, "text": text,
                                "disable_web_page_preview": "true"}).encode()
    u = "https://api.telegram.org/bot%s/sendMessage" % tok
    with urllib.request.urlopen(urllib.request.Request(u, data=d), timeout=20) as r:
        return json.loads(r.read().decode())

def price():
    b = {"symbols": {"tickers": [TICKER], "query": {"types": []}}, "columns": ["close"]}
    req = urllib.request.Request("https://scanner.tradingview.com/crypto/scan",
                                 data=json.dumps(b).encode(),
                                 headers={"Content-Type": "application/json",
                                          "User-Agent": "Mozilla/5.0"})
    with urllib.request.urlopen(req, timeout=20) as r:
        d = json.loads(r.read().decode())
    if not d.get("data"): raise RuntimeError("응답 없음")
    return float(d["data"][0]["d"][0])

def load():
    try: return json.load(open(STATE_F, encoding="utf-8"))
    except Exception: return {}
def save(s): json.dump(s, open(STATE_F,"w",encoding="utf-8"), ensure_ascii=False, indent=1)

def main():
    now = dt.datetime.now(dt.timezone.utc); ts = now.timestamp()
    st = load()
    try:
        p = price()
    except Exception as e:
        log("조회 실패: %s" % e); return

    hist = st.get("hist", []); hist.append([ts, p]); hist = hist[-6:]
    st["hist"] = hist; save(st)
    if len(hist) < 2:
        log("누적 중 | %.3f" % p); return

    gap = hist[-1][0] - hist[-2][0]
    if not (MIN_GAP <= gap <= MAX_GAP):
        log("간격 %.0f초, 판정 생략 | %.3f" % (gap, p)); return
    r = (hist[-1][1] / hist[-2][1] - 1) * 100

    alerts = []
    if r >= UP_5M: alerts.append("5분 급등 %+.2f%%" % r)
    if r <= DN_5M: alerts.append("5분 급락 %+.2f%%" % r)
    prev = hist[-2][1]
    for lv, nm in LEVELS:
        if prev < lv <= p: alerts.append("%s 상향 돌파 (%.2f)" % (nm, lv))
        if prev > lv >= p: alerts.append("%s 하향 이탈 (%.2f)" % (nm, lv))

    log("WTI %.3f (%+.2f%%)%s" % (p, r, " | " + ", ".join(alerts) if alerts else ""))
    if not alerts: return
    if ts - st.get("last_fire", 0) < COOLDOWN_MIN * 60:
        log("쿨다운"); return

    brent = p + 3.26   # 금요일 스프레드
    msg = ("유가 알림\n%s\n\nWTI %.2f\n브렌트 환산 %.2f\n5분 변화 %+.2f%%\n\n%s"
           % ("\n".join(alerts), p, brent, r,
              "이란 타격 실행 여부 확인" if r > 0 else "프리미엄 해소 진행"))
    try:
        telegram(msg); st["last_fire"] = ts; save(st); log("알림 발송")
    except Exception as e:
        log("텔레그램 실패: %s" % e)

if __name__ == "__main__":
    main()
