#!/usr/bin/env python3
"""
任务名称：更新 stride_phone_lead 飞书表格
执行频率：每天 8:00 AM
归属 Agent：小溪 (xiaoxi)

功能：
  1. 查询 vala_class.stride_phone_lead 全量数据（SELECT *，表增减字段自动适配）
  2. 更新飞书表格：
     - Sheet1 明细数据：全量明细，列名与字段自动跟随数据库表结构
     - Sheet2 按日期去重：created_at 转日期后按 account_id 去重计数
     - Sheet3 按source_l3去重：按 source_l3 对 account_id 去重计数
"""

import json, sys, os
from datetime import datetime, timezone, timedelta
from collections import defaultdict

# 配置
PG_HOST = "bj-postgres-16pob4sg.sql.tencentcdb.com"
PG_PORT = "28591"
PG_USER = "ai_member"
PG_DB = "vala_class"
PG_PASSWORD = os.environ.get("PG_VALA_CLASS_PASSWORD", "LdfjdjL83h3h3^$&**YGG*")

FEISHU_APP_ID = "cli_a929ae22e0b8dcc8"
FEISHU_APP_SECRET = "OtFjMy7p3qE3VvLbMdcWidwgHOnGD4FJ"
SPREADSHEET_TOKEN = "TWeHsCX6JhhsjntBagHcoJcJned"

SHEET_MINGXI = "1uDxsI"      # 明细数据
SHEET_DATE_DEDUP = "1uxp3G"  # 按日期去重
SHEET_SRC_DEDUP = "1urKus"   # 按source_l3去重

TZ = timezone(timedelta(hours=8))

LOG_FILE = "/var/log/update_stride_phone_lead.log"

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

def get_feishu_token():
    import urllib.request, urllib.error
    data = json.dumps({"app_id": FEISHU_APP_ID, "app_secret": FEISHU_APP_SECRET}).encode()
    req = urllib.request.Request(
        "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
        data=data,
        headers={"Content-Type": "application/json"}
    )
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())["tenant_access_token"]
    except Exception as e:
        log(f"获取飞书token失败: {e}")
        raise

def query_data():
    """查询 stride_phone_lead + stride_contact_bindings，返回 rows/cols/加微tel集合"""
    import psycopg2
    conn = psycopg2.connect(
        host=PG_HOST, port=PG_PORT, user=PG_USER,
        password=PG_PASSWORD, dbname=PG_DB
    )
    cur = conn.cursor()
    # 主表
    cur.execute("SELECT * FROM stride_phone_lead ORDER BY id")
    rows = cur.fetchall()
    cols = [desc[0] for desc in cur.description]
    # 加微绑定表 — 收集已加微的 tel_encrypt
    cur.execute("SELECT DISTINCT tel_encrypt FROM stride_contact_bindings WHERE tel_encrypt IS NOT NULL")
    wechat_tels = {r[0] for r in cur.fetchall()}
    cur.close()
    conn.close()
    return rows, cols, wechat_tels

def build_sheet1_data(rows, cols, wechat_tels):
    """明细数据 — 列名、列数完全跟随数据库表结构，末尾追加「是否加微」"""
    ts_cols = {"created_at", "updated_at"}
    idx_phone_enc = cols.index("phone_encrypt") if "phone_encrypt" in cols else -1
    data = [list(cols) + ["是否加微"]]
    for r in rows:
        row_data = []
        for i, col in enumerate(cols):
            val = r[i]
            if val is None:
                row_data.append("")
            elif col in ts_cols and isinstance(val, int) and val > 0:
                row_data.append(datetime.fromtimestamp(val, tz=TZ).strftime("%Y-%m-%d %H:%M:%S"))
            else:
                row_data.append(str(val))
        # 是否加微
        phone_enc = r[idx_phone_enc] if idx_phone_enc >= 0 else None
        row_data.append("是" if phone_enc in wechat_tels else "否")
        data.append(row_data)
    return data

def build_sheet2_data(rows, cols, wechat_tels):
    """按日期去重 account_id + 已加微数（补全日期范围，无数据填0）"""
    date_accts = defaultdict(set)
    date_wechat = defaultdict(set)
    idx_created = cols.index("created_at")
    idx_acc = cols.index("account_id")
    idx_phone_enc = cols.index("phone_encrypt")
    for r in rows:
        if r[idx_created]:
            dt = datetime.fromtimestamp(r[idx_created], tz=TZ).strftime("%Y-%m-%d")
            acct = r[idx_acc]
            date_accts[dt].add(acct)
            if r[idx_phone_enc] in wechat_tels:
                date_wechat[dt].add(acct)
    # 确定日期范围
    all_dates = sorted(date_accts.keys())
    if all_dates:
        start = datetime.strptime(all_dates[0], "%Y-%m-%d").date()
        end = datetime.strptime(all_dates[-1], "%Y-%m-%d").date()
        date_range = []
        d = start
        while d <= end:
            date_range.append(d.strftime("%Y-%m-%d"))
            d += timedelta(days=1)
    else:
        date_range = []
    data = [["日期", "去重account_id数", "已加微"]]
    for date in date_range:
        data.append([date, len(date_accts[date]), len(date_wechat[date])])
    return data

def build_sheet3_data(rows, cols, wechat_tels):
    """按source_l3去重 account_id + 已加微数"""
    src_accts = defaultdict(set)
    src_wechat = defaultdict(set)
    idx_src = cols.index("source_l3")
    idx_acc = cols.index("account_id")
    idx_phone_enc = cols.index("phone_encrypt")
    for r in rows:
        src = r[idx_src] or "(空)"
        src_accts[src].add(r[idx_acc])
        if r[idx_phone_enc] in wechat_tels:
            src_wechat[src].add(r[idx_acc])
    data = [["source_l3", "去重account_id数", "已加微"]]
    for src in sorted(src_accts.keys()):
        data.append([src, len(src_accts[src]), len(src_wechat[src])])
    return data

def clear_and_write(token, sheet_id, data, sheet_name):
    """清空并写入数据"""
    import urllib.request, urllib.error
    BASE = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets"
    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

    rows = len(data)
    cols = len(data[0]) if data else 0

    if rows == 0:
        log(f"  {sheet_name}: 无数据，清空")
        data = [["(无数据)"]]
        rows = 1
        cols = 1

    end_col = chr(ord('A') + cols - 1) if cols <= 26 else 'Z'
    end_row = rows
    full_range = f"{sheet_id}!A1:{end_col}{end_row}"

    body = {"valueRange": {"range": full_range, "values": data}}
    req = urllib.request.Request(
        f"{BASE}/{SPREADSHEET_TOKEN}/values",
        data=json.dumps(body).encode(),
        headers=headers,
        method="PUT"
    )
    try:
        with urllib.request.urlopen(req) as resp:
            result = json.loads(resp.read())
            code = result.get("code", -1)
            if code != 0:
                log(f"  {sheet_name}: 写入失败 code={code} msg={result.get('msg')}")
                return False
    except Exception as e:
        log(f"  {sheet_name}: 请求异常 {e}")
        return False

    log(f"  {sheet_name}: 写入 {rows-1} 行数据（含表头 {rows} 行）")
    return True

def main():
    # 查询数据
    log("开始查询数据库...")
    rows, cols, wechat_tels = query_data()
    log(f"查询完成，共 {len(rows)} 条记录，{len(cols)} 个字段：{cols}")
    log(f"加微绑定 tel_encrypt 共 {len(wechat_tels)} 个")

    # 获取飞书token
    log("获取飞书token...")
    token = get_feishu_token()

    # 写入Sheet1
    log("更新Sheet1 明细数据...")
    sheet1 = build_sheet1_data(rows, cols, wechat_tels)
    clear_and_write(token, SHEET_MINGXI, sheet1, "明细数据")

    # 写入Sheet2
    log("更新Sheet2 按日期去重...")
    sheet2 = build_sheet2_data(rows, cols, wechat_tels)
    clear_and_write(token, SHEET_DATE_DEDUP, sheet2, "按日期去重")

    # 写入Sheet3
    log("更新Sheet3 按source_l3去重...")
    sheet3 = build_sheet3_data(rows, cols, wechat_tels)
    clear_and_write(token, SHEET_SRC_DEDUP, sheet3, "按source_l3去重")

    log("全部更新完成！")

if __name__ == "__main__":
    main()
