#!/usr/bin/env python3
"""铸渊常驻Agent - 自动响应Notion工单"""
import os, sys, json, time, re
from datetime import datetime
import urllib.request, urllib.error

NOTION_TOKEN = "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"
NOTION_DB_ID = "663e4f29c7404d088f3a02fcc70b1418"
PORTAL = "http://127.0.0.1:3000"
POLL = 1800

def log(m): print(f'[{datetime.now().strftime("%H:%M:%S")}] {m}', flush=True)

def notion(method, path, data=None):
    url = 'https://api.notion.com/v1/' + path
    h = {'Authorization': 'Bearer ' + NOTION_TOKEN, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json'}
    b = json.dumps(data).encode() if data else None
    try:
        with urllib.request.urlopen(urllib.request.Request(url, b, h, method=method), timeout=15) as r:
            return json.loads(r.read())
    except:
        return None

def read_ticket(page_id):
    """读取单个工单的完整内容"""
    r = notion('GET', 'pages/' + page_id)
    if not r: return None
    p = r.get('properties', {})
    title = p.get('任务标题', {}).get('title', [{}])[0].get('plain_text', '?')
    content = ''
    dc = p.get('开发内容', {}).get('rich_text', [])
    if dc: content = dc[0].get('plain_text', '')
    code = ''
    nc = p.get('编号', {}).get('rich_text', [])
    if nc: code = nc[0].get('plain_text', '')
    return {'title': title, 'content': content, 'code': code, 'page_id': page_id}

def get_tickets():
    r = notion('POST', 'databases/' + NOTION_DB_ID + '/query', {
        'page_size': 20,
        'sorts': [{'timestamp': 'last_edited_time', 'direction': 'descending'}]
    })
    if not r: return []
    tks = []
    try:
        with open('/opt/guanghulab-repo/notion/tickets-cache.json') as f:
            cache = json.load(f)
            seen = set(t['id'] for t in cache.get('tickets', []))
    except:
        seen = set()
    for t in r.get('results', []):
        p = t.get('properties', {})
        agent = p.get('负责Agent', {}).get('select', {}).get('name', '')
        status = p.get('状态', {}).get('select', {}).get('name', '')
        title = p.get('任务标题', {}).get('title', [{}])[0].get('plain_text', '?')
        content = ''
        dev_content = p.get('开发内容', {}).get('rich_text', [])
        if dev_content:
            content = dev_content[0].get('plain_text', '')[:500]
        if agent in ('铸渊', '') and status in ('待开发', '开发中'):
            tks.append({
                'page_id': t['id'], 'title': title, 'status': status,
                'content': content, 'new': t['id'] not in seen
            })
    return tks

def reply(page_id, text):
    children = [{
        'object': 'block', 'type': 'callout',
        'callout': {
            'rich_text': [{'type': 'text', 'text': {'content': text[:1900]}}],
            'icon': {'emoji': '⚔️'}, 'color': 'orange_background'
        }
    }]
    return notion('PATCH', 'blocks/' + page_id + '/children', {'children': children}) is not None

def chat(prompt):
    import subprocess
    body = '{"persona":"zhuyuan","engine":"deepseek","message":"' + prompt.replace('"', '\"').replace("'", "\'")[:1500] + '","history":[],"user":"铸渊Agent","isTemp":false}'
    try:
        result = subprocess.run([
            'curl', '-s', '--max-time', '60',
            '-X', 'POST', PORTAL + '/api/chat-v2',
            '-H', 'Content-Type: application/json',
            '-d', body
        ], capture_output=True, text=True, timeout=70)
        matches = re.findall(r'data: (.+)', result.stdout)
        if matches:
            data = json.loads(matches[-1])
            return data.get('content', str(data)[:300])
        return result.stdout[:500]
    except Exception as e:
        log(f'Chat异常 {e}')
        return None

def process(t):
    log(f'处理: {t["title"][:30]}')
    p = '请你铸渊评估此工单：\n\n' + t['content'][:1000]
    r = chat(p)
    if not r: return
    msg = '⚔️铸渊评估 ' + datetime.now().strftime('%m-%d %H:%M') + '\n\n' + r[:1500]
    if reply(t['page_id'], msg):
        log('  ✅ 已回复')
    else:
        log('  ❌ 写入失败')

if __name__ == '__main__':
    log('⚔️铸渊Agent启动')
    log('轮询: 每' + str(POLL) + '秒')
    tks = get_tickets()
    if tks:
        log('待处理: ' + str(len(tks)) + '条')
        for t in tks: process(t)
    else:
        log('无待处理工单')
    log('进入主循环')
    log('=' * 40)
    while True:
        time.sleep(POLL)
        try:
            tks = get_tickets()
            new = [t for t in tks if t.get('new')]
            if new:
                log('U0001f195 新工单 ' + str(len(new)) + '条')
                for t in new: process(t)
        except KeyboardInterrupt:
            log('停止'); break
        except Exception as e:
            log('⚠ ' + str(e))
