"""
会员消费报表：2025-11-01 至今，按手机号归总，消费金额从高到低
口径：items_sum = table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money
台费拆分：通过 dws.cfg_area_category 配置，category_code='KTV' 为 K包，其余为一般包厢台费
会员信息：通过 member_id LEFT JOIN dim_member 获取 mobile/nickname
         （12月起 settlement_head.member_phone 为空，必须走 dim_member）
输出：CSV → export/SYSTEM/REPORTS/member_reports/
"""
import os
import csv
from dotenv import load_dotenv

load_dotenv()

PG_DSN = os.environ.get("TEST_DB_DSN") or os.environ.get("PG_DSN")
if not PG_DSN:
    raise RuntimeError("TEST_DB_DSN / PG_DSN 未配置")

SYSTEM_ANALYZE_ROOT = os.environ.get("SYSTEM_ANALYZE_ROOT")
if not SYSTEM_ANALYZE_ROOT:
    raise RuntimeError("SYSTEM_ANALYZE_ROOT 未配置")

import psycopg2

SQL = r"""
WITH date_range AS (
    SELECT '2025-11-01'::date AS start_date, CURRENT_DATE AS end_date
),

area_mapping AS (
    SELECT source_area_name, source_table_name, category_code
    FROM dws.cfg_area_category
    WHERE is_active = true AND match_type = 'EXACT'
),

-- 先筛出有会员的结算单（member_id 有值，或 member_phone 有值）
settle_ids AS (
    SELECT sh.order_settle_id
    FROM dwd.dwd_settlement_head sh
    CROSS JOIN date_range dr
    WHERE sh.settle_type IN (1, 3)
      AND sh.pay_time >= dr.start_date
      AND sh.pay_time < dr.end_date + 1
      AND (
          (sh.member_id IS NOT NULL AND sh.member_id != 0)
          OR (sh.member_phone IS NOT NULL AND sh.member_phone != '')
      )
),

table_fee_split AS (
    SELECT
        tfl.order_settle_id,
        SUM(CASE WHEN COALESCE(am.category_code, 'OTHER') = 'KTV'
                 THEN tfl.ledger_amount ELSE 0 END) AS k_room_fee,
        SUM(CASE WHEN COALESCE(am.category_code, 'OTHER') != 'KTV'
                 THEN tfl.ledger_amount ELSE 0 END) AS normal_table_fee
    FROM dwd.dwd_table_fee_log tfl
    INNER JOIN settle_ids si ON tfl.order_settle_id = si.order_settle_id
    LEFT JOIN dwd.dim_table dt
        ON dt.table_id = tfl.site_table_id AND dt.scd2_is_current = 1
    LEFT JOIN area_mapping am
        ON tfl.site_table_area_name = am.source_area_name
       AND dt.table_name = am.source_table_name
    WHERE tfl.is_delete = 0
    GROUP BY tfl.order_settle_id
),

-- 关联 dim_member 获取手机号，优先 dim_member.mobile，回退 settlement_head.member_phone
consumption AS (
    SELECT
        sh.order_settle_id,
        COALESCE(NULLIF(dm.mobile, ''), NULLIF(sh.member_phone, '')) AS phone,
        sh.pay_time,
        COALESCE(sh.table_charge_money, 0)
          + COALESCE(sh.goods_money, 0)
          + COALESCE(sh.assistant_pd_money, 0)
          + COALESCE(sh.assistant_cx_money, 0)
          + COALESCE(sh.electricity_money, 0) AS items_sum,
        COALESCE(sh.goods_money, 0) AS goods_money,
        COALESCE(sh.assistant_pd_money, 0) + COALESCE(sh.assistant_cx_money, 0) AS assistant_money
    FROM dwd.dwd_settlement_head sh
    CROSS JOIN date_range dr
    LEFT JOIN dwd.dim_member dm
        ON dm.member_id = sh.member_id AND dm.scd2_is_current = 1
    WHERE sh.settle_type IN (1, 3)
      AND sh.pay_time >= dr.start_date
      AND sh.pay_time < dr.end_date + 1
      AND (
          (sh.member_id IS NOT NULL AND sh.member_id != 0)
          OR (sh.member_phone IS NOT NULL AND sh.member_phone != '')
      )
),

-- 过滤掉最终仍无手机号的记录
consumption_with_phone AS (
    SELECT * FROM consumption WHERE phone IS NOT NULL
),

monthly AS (
    SELECT
        c.phone,
        EXTRACT(YEAR FROM c.pay_time)::int AS yr,
        EXTRACT(MONTH FROM c.pay_time)::int AS mo,
        SUM(c.items_sum) AS month_total,
        SUM(c.goods_money) AS month_goods,
        SUM(c.assistant_money) AS month_assistant,
        SUM(COALESCE(tf.k_room_fee, 0)) AS month_k_room,
        SUM(COALESCE(tf.normal_table_fee, 0)) AS month_normal_table
    FROM consumption_with_phone c
    LEFT JOIN table_fee_split tf ON c.order_settle_id = tf.order_settle_id
    GROUP BY c.phone, yr, mo
),

member_agg AS (
    SELECT
        phone,
        SUM(month_total) AS total_consumption,
        SUM(CASE WHEN yr = 2025 AND mo = 11 THEN month_total ELSE 0 END) AS m11,
        SUM(CASE WHEN yr = 2025 AND mo = 12 THEN month_total ELSE 0 END) AS m12,
        SUM(CASE WHEN yr = 2026 AND mo = 1 THEN month_total ELSE 0 END) AS m01,
        SUM(CASE WHEN yr = 2026 AND mo = 2 THEN month_total ELSE 0 END) AS m02,
        SUM(CASE WHEN yr = 2026 AND mo = 3 THEN month_total ELSE 0 END) AS m03,
        SUM(month_k_room) AS k_room_total,
        SUM(month_normal_table) AS normal_table_total,
        SUM(month_assistant) AS assistant_total,
        SUM(month_goods) AS goods_total
    FROM monthly
    GROUP BY phone
),

-- 昵称：合并 dim_member.nickname 和 settlement_head.member_name
member_names AS (
    SELECT
        COALESCE(NULLIF(dm.mobile, ''), NULLIF(sh.member_phone, '')) AS phone,
        STRING_AGG(
            DISTINCT COALESCE(NULLIF(dm.nickname, ''), NULLIF(sh.member_name, '')),
            ' | '
            ORDER BY COALESCE(NULLIF(dm.nickname, ''), NULLIF(sh.member_name, ''))
        ) FILTER (
            WHERE COALESCE(NULLIF(dm.nickname, ''), NULLIF(sh.member_name, '')) IS NOT NULL
        ) AS names
    FROM dwd.dwd_settlement_head sh
    CROSS JOIN date_range dr
    LEFT JOIN dwd.dim_member dm
        ON dm.member_id = sh.member_id AND dm.scd2_is_current = 1
    WHERE sh.settle_type IN (1, 3)
      AND sh.pay_time >= dr.start_date
      AND sh.pay_time < dr.end_date + 1
      AND (
          (sh.member_id IS NOT NULL AND sh.member_id != 0)
          OR (sh.member_phone IS NOT NULL AND sh.member_phone != '')
      )
      AND COALESCE(NULLIF(dm.mobile, ''), NULLIF(sh.member_phone, '')) IS NOT NULL
    GROUP BY phone
)

SELECT
    COALESCE(mn.names, '') AS "会员昵称",
    ma.phone AS "手机号",
    ROUND(ma.total_consumption, 2) AS "11月至今共消费",
    ROUND(ma.m11, 2) AS "11月消费共计",
    ROUND(ma.m12, 2) AS "12月消费共计",
    ROUND(ma.m01, 2) AS "1月消费共计",
    ROUND(ma.m02, 2) AS "2月消费共计",
    ROUND(ma.m03, 2) AS "3月消费共计",
    ROUND(ma.k_room_total, 2) AS "K包",
    CASE WHEN ma.total_consumption > 0
         THEN ROUND(ma.k_room_total / ma.total_consumption * 100, 1)
         ELSE 0 END AS "K包占比%",
    ROUND(ma.normal_table_total, 2) AS "一般包厢台费",
    CASE WHEN ma.total_consumption > 0
         THEN ROUND(ma.normal_table_total / ma.total_consumption * 100, 1)
         ELSE 0 END AS "一般包厢台费占比%",
    ROUND(ma.assistant_total, 2) AS "助教费",
    CASE WHEN ma.total_consumption > 0
         THEN ROUND(ma.assistant_total / ma.total_consumption * 100, 1)
         ELSE 0 END AS "助教费占比%",
    ROUND(ma.goods_total, 2) AS "商品费",
    CASE WHEN ma.total_consumption > 0
         THEN ROUND(ma.goods_total / ma.total_consumption * 100, 1)
         ELSE 0 END AS "商品费占比%"
FROM member_agg ma
LEFT JOIN member_names mn ON ma.phone = mn.phone
ORDER BY ma.total_consumption DESC
"""


def run_report():
    with psycopg2.connect(PG_DSN, connect_timeout=15, options="-c statement_timeout=300000") as conn:
        with conn.cursor() as cur:
            cur.execute(SQL)
            columns = [desc[0] for desc in cur.description]
            rows = cur.fetchall()

    report_dir = os.path.join(os.path.dirname(SYSTEM_ANALYZE_ROOT), "member_reports")
    os.makedirs(report_dir, exist_ok=True)

    csv_path = os.path.join(report_dir, "member_consumption_202511_to_now.csv")
    with open(csv_path, "w", newline="", encoding="utf-8-sig") as f:
        writer = csv.writer(f)
        writer.writerow(columns)
        writer.writerows(rows)

    print(f"✅ 报表已生成: {csv_path}")
    print(f"   共 {len(rows)} 位会员")

    print(f"\n{'='*200}")
    header = " | ".join(f"{c:>14}" if i > 1 else f"{c:<20}" for i, c in enumerate(columns))
    print(header)
    print(f"{'='*200}")
    for row in rows[:20]:
        line = " | ".join(
            f"{str(v):<20}" if i <= 1 else f"{str(v):>14}"
            for i, v in enumerate(row)
        )
        print(line)
    if len(rows) > 20:
        print(f"... 还有 {len(rows) - 20} 行（见 CSV 文件）")


if __name__ == "__main__":
    run_report()
