#!/usr/bin/env python3
"""
直购表全量刷新（小红书店铺 dianpu-xhs + stream-xhs）
触发：full_refresh 时先跑此脚本，再跑 refresh_order_summary.py
归属：小溪 (xiaoxi)

直购用户不依赖销售表手机号匹配，直接从 DB 查 key_from 含 dianpu-xhs/stream-xhs 的订单。
"""
import json, time, os, requests, psycopg2
from datetime import datetime

# ── 配置 ──
APP_ID = "cli_a929ae22e0b8dcc8"
APP_SECRET = "OtFjMy7p3qE3VvLbMdcWidwgHOnGD4FJ"
SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug"
DIRECT_SHEET = "1sosYE"

HEADER = [
    "销售归属", "微信昵称", "进线日期", "体验节数", "手机号", "用户年级",
    "课史/跟进", "用户ID", "注册日期", "下载渠道", "是否下单", "下单日期",
    "成交渠道", "产品", "下单金额", "退款金额", "实际收入", "激活课程",
    "当前行课进度", "最近行课时间", "累计学习时长", "更新时间", "渠道归属", "有效成单"
]


def _get_pg_password():
    secrets_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "secrets.env")
    with open(secrets_path) as f:
        for line in f:
            if line.startswith("PG_ONLINE_PASSWORD="):
                return line.strip().split("=", 1)[1].strip('"').strip("'")
    raise RuntimeError("PG_ONLINE_PASSWORD not found in secrets.env")


PG_CONFIG = {
    "host": "bj-postgres-16pob4sg.sql.tencentcdb.com", "port": 28591,
    "user": "ai_member", "password": _get_pg_password(), "database": "vala_bi",
}


def get_token():
    r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
                      json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=15)
    return r.json()["tenant_access_token"]


def put_values(token, sheet_id, range_str, values, retries=3):
    url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values"
    body = {"valueRange": {"range": f"{sheet_id}!{range_str}", "values": values}}
    for attempt in range(retries):
        r = requests.put(url, headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }, json=body, timeout=30)
        result = r.json()
        if result.get("code") == 0:
            return True
        time.sleep(1)
    return False


def main():
    print(f"[{datetime.now():%Y-%m-%d %H:%M:%S}] 直购表刷新 启动")

    # ── Step 1: DB 查询 ──
    conn = psycopg2.connect(**PG_CONFIG, connect_timeout=30)
    cur = conn.cursor()

    cur.execute("""
        SELECT 
            o.account_id,
            a.name,
            a.tel,
            a.created_at,
            a.download_channel,
            o.pay_success_date,
            o.key_from,
            o.goods_name,
            o.pay_amount_int,
            o.order_status,
            COALESCE(r.refund_amount_int, 0) as refund_amount
        FROM bi_vala_order o
        JOIN bi_vala_app_account a ON o.account_id = a.id AND a.status = 1
        LEFT JOIN bi_refund_order r ON o.trade_no = r.trade_no AND r.status = 3
        WHERE o.pay_success_date IS NOT NULL
          AND o.order_status IN (3,4)
          AND (o.key_from LIKE '%dianpu-xhs%' OR o.key_from LIKE '%stream-xhs%')
        ORDER BY o.pay_success_date DESC
    """)
    orders = cur.fetchall()

    # Dedup by account_id
    seen = set()
    unique_orders = []
    for o in orders:
        if o[0] not in seen:
            seen.add(o[0])
            unique_orders.append(o)

    uids = [o[0] for o in unique_orders]

    # 体验节数
    cur.execute("""
        SELECT account_id, COUNT(*) FROM bi_user_course_detail
        WHERE account_id = ANY(%s) AND expire_time IS NULL AND deleted_at IS NULL
        GROUP BY account_id
    """, (uids,))
    exp_map = {r[0]: r[1] for r in cur.fetchall()}

    # 激活课程
    cur.execute("""
        SELECT DISTINCT ON (account_id) account_id, course_level
        FROM bi_user_course_detail
        WHERE account_id = ANY(%s) AND expire_time IS NOT NULL AND deleted_at IS NULL
        ORDER BY account_id, expire_time DESC
    """, (uids,))
    course_map = {r[0]: r[1] for r in cur.fetchall()}

    # 学习进度
    cur.execute("""
        SELECT DISTINCT ON (c.user_id) a.id, blul.course_level, blul.course_season,
               blul.course_unit, blul.course_lesson, c.created_at
        FROM bi_user_chapter_play_record_0 c
        JOIN bi_vala_app_character ch ON c.user_id = ch.id
        JOIN bi_vala_app_account a ON ch.account_id = a.id
        JOIN bi_level_unit_lesson blul ON c.chapter_id = blul.id
        WHERE a.id = ANY(%s) AND c.play_status = 1
        ORDER BY c.user_id, c.created_at DESC
    """, (uids,))
    study_map = {}
    study_time_map = {}
    for r in cur.fetchall():
        aid = r[0]
        if aid not in study_map:
            study_map[aid] = f"{r[1]}-{r[2]}-{r[3]}-{r[4]}"
            study_time_map[aid] = str(r[5])[:19]

    # 学习时长
    cur.execute("""
        SELECT a.id, SUM(comp.interval_time)
        FROM bi_user_chapter_play_record_0 c
        JOIN bi_vala_app_character ch ON c.user_id = ch.id
        JOIN bi_vala_app_account a ON ch.account_id = a.id
        JOIN bi_user_component_play_record_0 comp ON c.chapter_unique_id = comp.chapter_unique_id
        WHERE a.id = ANY(%s) AND c.play_status = 1
        GROUP BY a.id
    """, (uids,))
    time_map = {r[0]: r[1] for r in cur.fetchall()}

    cur.close()
    conn.close()

    # ── Step 2: 构建行 ──
    now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    new_rows = []

    for o in unique_orders:
        uid = o[0]
        name = o[1] or ""
        tel = o[2] or ""
        reg = str(o[3])[:10] if o[3] else ""
        dl = o[4] or ""
        l_date_raw = o[5]
        l_date = str(l_date_raw)[:10] if l_date_raw else ""
        key_from = o[6]
        goods = o[7].strip() if o[7] else ""
        amount = o[8] / 100
        refund = o[10] / 100 if o[10] else 0

        # 全额退跳过
        if refund > 0 and refund >= amount:
            continue

        exp = exp_map.get(uid, 0)
        course = course_map.get(uid, "")
        study = study_map.get(uid, "")
        last_study = study_time_map.get(uid, "")
        total_min = round(time_map.get(uid, 0) / 60000, 1) if time_map.get(uid, 0) else ""
        gsv = amount - refund

        row = [
            "直购", name, "", exp, tel, "", "", uid, reg, dl,
            "是", l_date, key_from, goods, amount,
            refund if refund > 0 else "", gsv, course, study,
            last_study, total_min, now_str, "直购", 1,
        ]
        new_rows.append(row)

    # 按下单日期降序
    new_rows.sort(key=lambda r: r[11], reverse=True)

    print(f"有效直购订单: {len(new_rows)}")

    # ── Step 3: 写入飞书 ──
    token = get_token()

    # 写表头
    put_values(token, DIRECT_SHEET, "A1:X1", [HEADER])

    # 写数据
    for batch_start in range(0, len(new_rows), 20):
        batch = new_rows[batch_start:batch_start + 20]
        sr = 2 + batch_start
        er = sr + len(batch) - 1
        put_values(token, DIRECT_SHEET, f"A{sr}:X{er}", batch)
        time.sleep(0.3)

    # 清除多余旧行
    total = len(new_rows)
    clear_start = 2 + total
    empty = [[""] * 24 for _ in range(50)]
    put_values(token, DIRECT_SHEET, f"A{clear_start}:X{clear_start + 49}", empty)

    print(f"[{datetime.now():%Y-%m-%d %H:%M:%S}] ✅ 直购表刷新完成 ({total} 行)")


if __name__ == "__main__":
    main()
