#!/usr/bin/env python3
"""
B档一方回传 · 非小红书渠道 + 小红书达人密集成单
时间窗: 2025-09-01 ~ 2026-06-03
输出: plaintext CSV → phone_encrypt → MD5上传CSV
"""
import os, sys, csv, psycopg2
from datetime import date, datetime
from collections import defaultdict

SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, SCRIPTS_DIR)
from phone_encrypt import phone_md5, decrypt_phone

OUTPUT_DIR = os.path.join(os.path.dirname(SCRIPTS_DIR), "output", "yifang_export")
os.makedirs(OUTPUT_DIR, exist_ok=True)

# ── 渠道定义 ──
CHANNELS = {
    "douyin_daren": {
        "name": "抖音达人",
        "prefix": "B1_douyin_daren",
        "key_from_like": "newmedia-daren-douyin%",
        "account_key_from_like": "newmedia-daren-douyin%",
    },
    "wxxd_daren": {
        "name": "视频号达人",
        "prefix": "B2_wxxd_daren",
        "key_from_like": "newmedia-daren-wxxd%",
        "account_key_from_like": "newmedia-daren-wxxd%",
    },
    "wwxx_shop": {
        "name": "万物店",
        "prefix": "B3_wwxx_shop",
        "key_from_like": "newmedia-dianpu-wwxx-0-0",
        "account_key_from_like": "newmedia-dianpu-wwxx-0-0",
    },
    "app_internal": {
        "name": "端内",
        "prefix": "B4_app_internal",
        "key_from_like": None,  # IN 列表
        "key_from_in": ["app-active-h5-0-0", "app-sales-bj-qhm-0"],
        "account_key_from_like": None,
        "account_key_from_in": ["app-active-h5-0-0", "app-sales-bj-qhm-0"],
    },
    "sales_adp": {
        "name": "销售渠道",
        "prefix": "B5_sales_adp",
        "key_from_like": "sales-adp%",
        "account_key_from_like": "sales-adp%",
    },
}

# 小红书达人密集成单
XHS_DAREN_PREFIX = "B6_xhs_daren_paid"
XHS_DAREN_KEY_LIKE = ["newmedia-daren-xhs%", "newmedia-dianpu-xhs-0-0"]

TIME_START = "2025-09-01"
TIME_END = "2026-06-03"

PLAINTEXT_HEADER = ["手机号", "行为时间", "行为类型", "样本渠道", "实付金额", "额外信息"]
UPLOAD_HEADER = ["用户ID（必填）", "行为时间（选填）", "行为类型（选填）", "样本渠道（选填）", "实付金额（选填）", "额外信息（选填）"]


def get_pg_conn():
    secrets_path = os.path.join(SCRIPTS_DIR, "..", "secrets.env")
    with open(secrets_path) as f:
        pg_pass = None
        for line in f:
            if line.startswith("PG_ONLINE_PASSWORD="):
                pg_pass = line.strip().split("=", 1)[1].strip("'\"")
    return psycopg2.connect(
        host="bj-postgres-16pob4sg.sql.tencentcdb.com",
        port=28591,
        user="ai_member",
        password=pg_pass,
        dbname="vala_bi"
    )


def clean_phone(val):
    if not val:
        return None
    val = str(val).strip().replace(" ", "").replace("-", "").replace("'", "")
    if "e" in val.lower() or "E" in val:
        try:
            val = str(int(float(val)))
        except:
            return None
    digits = "".join(c for c in val if c.isdigit())
    if len(digits) == 11 and digits.startswith("1"):
        return digits
    return None


def write_csv(filename, rows, is_upload=False):
    """rows: list of dicts"""
    path = os.path.join(OUTPUT_DIR, filename)
    header = UPLOAD_HEADER if is_upload else PLAINTEXT_HEADER
    with open(path, "w", newline="", encoding="utf-8-sig") as f:
        writer = csv.writer(f)
        writer.writerow(header)
        for r in rows:
            phone = r["phone"]
            user_id = phone_md5(phone) if is_upload else phone
            writer.writerow([
                user_id,
                r["event_time"],
                r["behavior"],
                r["channel"],
                r["amount"],
                r["extra"],
            ])
    return path


def build_where_clause(ch_cfg, table_alias="o"):
    """构建 WHERE 条件"""
    if ch_cfg.get("key_from_in"):
        placeholders = ",".join([f"'{v}'" for v in ch_cfg["key_from_in"]])
        return f"{table_alias}.key_from IN ({placeholders})"
    elif ch_cfg.get("key_from_like"):
        return f"{table_alias}.key_from LIKE '{ch_cfg['key_from_like']}'"
    return "1=0"


def build_account_where(ch_cfg, table_alias="a"):
    """构建 account 表 WHERE 条件"""
    if ch_cfg.get("account_key_from_in"):
        placeholders = ",".join([f"'{v}'" for v in ch_cfg["account_key_from_in"]])
        return f"{table_alias}.key_from IN ({placeholders})"
    elif ch_cfg.get("account_key_from_like"):
        return f"{table_alias}.key_from LIKE '{ch_cfg['account_key_from_like']}'"
    return "1=0"


def main():
    conn = get_pg_conn()
    cur = conn.cursor()

    all_b_phones = set()  # 用于 overlap 统计

    for ch_key, ch_cfg in CHANNELS.items():
        print(f"\n{'='*60}")
        print(f"处理渠道: {ch_cfg['name']} ({ch_key})")
        
        order_where = build_where_clause(ch_cfg)
        account_where = build_account_where(ch_cfg)

        # ── 留资包：从 bi_vala_app_account 查注册用户 ──
        print("  查询留资用户...")
        cur.execute(f"""
            SELECT a.id::text, a.tel_encrypt, a.created_at::date
            FROM bi_vala_app_account a
            WHERE a.status = 1 AND a.deleted_at IS NULL
              AND a.created_at >= '{TIME_START}'
              AND a.created_at < '{TIME_END}'::date + 1
              AND ({account_where})
            ORDER BY a.created_at
        """)
        lead_rows_raw = cur.fetchall()
        print(f"  留资用户(原始): {len(lead_rows_raw)}")

        # 去重：同一手机号取最早注册
        lead_map = {}
        for aid, tel_enc, created_date in lead_rows_raw:
            tel = decrypt_phone(tel_enc) if tel_enc else None
            phone = clean_phone(tel)
            if not phone:
                continue
            if phone not in lead_map or (created_date and created_date < lead_map[phone]["date"]):
                lead_map[phone] = {"date": created_date, "aid": aid}

        lead_rows = []
        for phone, info in lead_map.items():
            lead_rows.append({
                "phone": phone,
                "event_time": str(info["date"]) if info["date"] else "",
                "behavior": "留资",
                "channel": ch_cfg["name"],
                "amount": "",
                "extra": f"uid={info['aid']}",
            })
            all_b_phones.add(phone)

        plaintext_path = write_csv(f"plaintext_{ch_cfg['prefix']}_lead.csv", lead_rows)
        upload_path = write_csv(f"{ch_cfg['prefix']}_lead.csv", lead_rows, is_upload=True)
        print(f"  留资: {len(lead_rows)} 行 → {upload_path}")

        # ── 成单包：从 bi_vala_order 查 ──
        print("  查询成单用户...")
        cur.execute(f"""
            SELECT DISTINCT ON (o.account_id)
                o.account_id::text, a.tel_encrypt, o.pay_success_date::date,
                o.pay_amount_int, o.key_from
            FROM bi_vala_order o
            JOIN bi_vala_app_account a ON o.account_id = a.id AND a.status = 1 AND a.deleted_at IS NULL
            WHERE o.pay_success_date >= '{TIME_START}'
              AND o.pay_success_date < '{TIME_END}'::date + 1
              AND o.order_status IN (3, 4)
              AND ({order_where})
            ORDER BY o.account_id, o.pay_success_date DESC
        """)
        paid_rows_raw = cur.fetchall()
        print(f"  成单用户(原始): {len(paid_rows_raw)}")

        paid_rows = []
        for aid, tel_enc, pay_date, amount_int, key_from in paid_rows_raw:
            tel = decrypt_phone(tel_enc) if tel_enc else None
            phone = clean_phone(tel)
            if not phone:
                continue
            amount_yuan = f"{amount_int / 100:.2f}" if amount_int else ""
            paid_rows.append({
                "phone": phone,
                "event_time": str(pay_date) if pay_date else "",
                "behavior": "购买",
                "channel": ch_cfg["name"],
                "amount": amount_yuan,
                "extra": f"uid={aid} | key_from={key_from}",
            })
            all_b_phones.add(phone)

        plaintext_path = write_csv(f"plaintext_{ch_cfg['prefix']}_paid.csv", paid_rows)
        upload_path = write_csv(f"{ch_cfg['prefix']}_paid.csv", paid_rows, is_upload=True)
        print(f"  成单: {len(paid_rows)} 行 → {upload_path}")

    # ── B6: 小红书达人密集成单 ──
    print(f"\n{'='*60}")
    print("处理: 小红书达人密集成单 (B6)")

    xhs_where = " OR ".join([f"o.key_from LIKE '{lk}'" for lk in XHS_DAREN_KEY_LIKE])
    cur.execute(f"""
        SELECT o.account_id::text, a.tel_encrypt, o.pay_success_date::date,
               o.pay_amount_int, o.key_from
        FROM bi_vala_order o
        JOIN bi_vala_app_account a ON o.account_id = a.id AND a.status = 1 AND a.deleted_at IS NULL
        WHERE o.pay_success_date >= '{TIME_START}'
          AND o.pay_success_date < '{TIME_END}'::date + 1
          AND o.order_status IN (3, 4)
          AND ({xhs_where})
        ORDER BY o.pay_success_date DESC
    """)
    xhs_rows_raw = cur.fetchall()
    print(f"  成单(原始): {len(xhs_rows_raw)}")

    # 去重：同一account_id取最近一单
    xhs_paid_map = {}
    for aid, tel_enc, pay_date, amount_int, key_from in xhs_rows_raw:
        tel = decrypt_phone(tel_enc) if tel_enc else None
        phone = clean_phone(tel)
        if not phone:
            continue
        if aid not in xhs_paid_map or (pay_date and pay_date > xhs_paid_map[aid]["date"]):
            amount_yuan = f"{amount_int / 100:.2f}" if amount_int else ""
            xhs_paid_map[aid] = {
                "phone": phone,
                "date": pay_date,
                "amount": amount_yuan,
                "key_from": key_from,
            }

    xhs_paid_rows = []
    for aid, info in xhs_paid_map.items():
        xhs_paid_rows.append({
            "phone": info["phone"],
            "event_time": str(info["date"]) if info["date"] else "",
            "behavior": "购买",
            "channel": "小红书达人",
            "amount": info["amount"],
            "extra": f"uid={aid} | key_from={info['key_from']}",
        })

    plaintext_path = write_csv(f"plaintext_{XHS_DAREN_PREFIX}.csv", xhs_paid_rows)
    upload_path = write_csv(f"{XHS_DAREN_PREFIX}.csv", xhs_paid_rows, is_upload=True)
    print(f"  成单: {len(xhs_paid_rows)} 行 → {upload_path}")

    # ── QA: B档手机号与A1重合 ──
    print(f"\n{'='*60}")
    print("QA: B档与A1重合分析")

    # 读取A1明文
    a1_path = os.path.join(OUTPUT_DIR, "plaintext_A1_wala_lead_xhs_202509-20260603.csv")
    a1_phones = set()
    if os.path.exists(a1_path):
        with open(a1_path, encoding="utf-8-sig") as f:
            reader = csv.reader(f)
            next(reader)  # skip header
            for row in reader:
                if row:
                    a1_phones.add(row[0])
        print(f"  A1手机号: {len(a1_phones)}")
    else:
        print("  A1文件不存在，跳过")

    overlap = all_b_phones & a1_phones
    print(f"  B档总手机号(去重): {len(all_b_phones)}")
    print(f"  B档∩A1重合: {len(overlap)}")
    print(f"  重合率: {len(overlap)/len(a1_phones)*100:.1f}% (相对A1)")

    # 输出overlap清单
    overlap_path = os.path.join(OUTPUT_DIR, "B_vs_A1_overlap.csv")
    with open(overlap_path, "w", newline="", encoding="utf-8-sig") as f:
        writer = csv.writer(f)
        writer.writerow(["手机号_MD5", "在A1", "在B档"])
        for phone in sorted(overlap):
            writer.writerow([phone_md5(phone), "Y", "Y"])
    print(f"  Overlap清单: {overlap_path} ({len(overlap)} 行)")

    cur.close()
    conn.close()

    # ── 汇总 ──
    print(f"\n{'='*60}")
    print("=== B档导出完成 ===")
    for ch_key, ch_cfg in CHANNELS.items():
        lead_path = os.path.join(OUTPUT_DIR, f"{ch_cfg['prefix']}_lead.csv")
        paid_path = os.path.join(OUTPUT_DIR, f"{ch_cfg['prefix']}_paid.csv")
        lead_cnt = sum(1 for _ in open(lead_path)) - 1 if os.path.exists(lead_path) else 0
        paid_cnt = sum(1 for _ in open(paid_path)) - 1 if os.path.exists(paid_path) else 0
        print(f"  {ch_cfg['name']}: 留资{lead_cnt}行 | 成单{paid_cnt}行")
    xhs_path = os.path.join(OUTPUT_DIR, f"{XHS_DAREN_PREFIX}.csv")
    xhs_cnt = sum(1 for _ in open(xhs_path)) - 1 if os.path.exists(xhs_path) else 0
    print(f"  小红书达人密集成单: {xhs_cnt}行")
    print(f"  B档∩A1重合: {len(overlap)}人")
    print(f"输出目录: {OUTPUT_DIR}")


if __name__ == "__main__":
    main()
