#!/usr/bin/env python3
"""卡删除脚本：读取 ICCID 列表，生成数据库删除 SQL 和 Redis 轮询清理命令。

用法:
    python3 remove_cards.py --input <csv文件> [--output-dir output]

CSV 格式: 纯文本，每行一个 ICCID，首行可有 "iccid" 表头（自动跳过）

输出:
    output/remove_cards_db.sql          -- 数据库软删 + 标识符硬删 SQL（事务封装）
    output/remove_cards_redis_gen.sql   -- 在数据库执行后把输出通过 redis-cli 清理轮询队列
"""
from __future__ import annotations

import argparse
import sys
from datetime import datetime
from pathlib import Path


def load_iccids(csv_path: Path) -> list[str]:
    """读取 CSV 文件中的 ICCID 列表，自动跳过空行和表头。"""
    iccids: list[str] = []
    with csv_path.open(encoding="utf-8") as f:
        for lineno, raw in enumerate(f, 1):
            line = raw.strip()
            if not line:
                continue
            # 跳过纯字母表头（如 "iccid"）
            if lineno == 1 and not line.isdigit() and not line.startswith("8"):
                print(f"[remove] 跳过表头: {line!r}", file=sys.stderr)
                continue
            iccids.append(line)
    return iccids


def sql_in_list(iccids: list[str]) -> str:
    """生成 SQL IN 列表字符串，如 '898...', '898...'"""
    return ", ".join(f"'{i}'" for i in iccids)


def generate_db_sql(iccids: list[str], generated_at: str) -> str:
    in_list = sql_in_list(iccids)
    count = len(iccids)
    return f"""\
-- ============================================================
-- 迁移卡删除脚本 (数据库部分)
-- 生成时间: {generated_at}
-- 卡数量  : {count}
-- 执行前请先用 remove_cards_redis_gen.sql 生成 Redis 清理命令并执行
-- 建议执行: psql ... -1 -f <此文件>
-- ============================================================

BEGIN;

-- 临时表：本次要删除的卡
CREATE TEMP TABLE tmp_remove_cards AS
SELECT id, iccid
FROM tb_iot_card
WHERE iccid IN ({in_list});

DO $$ BEGIN
    RAISE NOTICE '本次将删除 % 张卡（共输入 {count} 个 ICCID）', (SELECT COUNT(*) FROM tmp_remove_cards);
END $$;

-- 1. 删除套餐使用记录
DELETE FROM tb_package_usage
WHERE iot_card_id IN (SELECT id FROM tmp_remove_cards);

-- 2. 删除订单
DELETE FROM tb_order
WHERE iot_card_id IN (SELECT id FROM tmp_remove_cards);

-- 3. 删除分配记录
DELETE FROM tb_asset_allocation_record
WHERE asset_type = 'iot_card'
  AND asset_id IN (SELECT id FROM tmp_remove_cards);

-- 4. 删除资产钱包
DELETE FROM tb_asset_wallet
WHERE resource_type = 'iot_card'
  AND resource_id IN (SELECT id FROM tmp_remove_cards);

-- 5. 删除设备绑卡关系
DELETE FROM tb_device_sim_binding
WHERE iot_card_id IN (SELECT id FROM tmp_remove_cards);

-- 6. 删除资产标识符
DELETE FROM tb_asset_identifier
WHERE asset_type = 'iot_card'
  AND asset_id IN (SELECT id FROM tmp_remove_cards);

-- 7. 删除卡本体（最后执行）
DELETE FROM tb_iot_card
WHERE id IN (SELECT id FROM tmp_remove_cards);

COMMIT;
"""


def generate_redis_gen_sql(iccids: list[str], generated_at: str) -> str:
    in_list = sql_in_list(iccids)
    count = len(iccids)
    return f"""\
-- ============================================================
-- 轮询队列清理命令生成 SQL
-- 生成时间: {generated_at}
-- 卡数量  : {count}
-- 执行方式:
--   psql ... -t -A -c "$(cat remove_cards_redis_gen.sql)" | redis-cli --pipe
-- 或:
--   psql ... -t -A -f remove_cards_redis_gen.sql | redis-cli
-- ============================================================

WITH cards AS (
    SELECT id FROM tb_iot_card
    WHERE iccid IN ({in_list})
),
task_types(task_type) AS (
    VALUES
        ('polling:realname'),
        ('polling:carddata'),
        ('polling:package'),
        ('polling:protect'),
        ('polling:card_status')
)
SELECT format('ZREM polling:shard:%s:queue:%s %s', id % 16, task_type, id)
FROM cards CROSS JOIN task_types
UNION ALL
SELECT format('DEL polling:card:%s', id)
FROM cards
UNION ALL
SELECT format('LREM polling:manual:%s 0 %s', task_type, id)
FROM cards CROSS JOIN task_types
UNION ALL
SELECT format('SREM polling:manual:dedupe:%s %s', task_type, id)
FROM cards CROSS JOIN task_types;
"""


def main() -> int:
    parser = argparse.ArgumentParser(description="迁移卡删除脚本：生成删除 SQL 和 Redis 清理命令")
    parser.add_argument("--input", required=True, help="ICCID 列表 CSV 文件路径")
    parser.add_argument("--output-dir", default="output", help="输出目录（默认 output）")
    args = parser.parse_args()

    base = Path(__file__).resolve().parent
    input_path = Path(args.input)
    if not input_path.is_absolute():
        input_path = base / input_path
    output_dir = (base / args.output_dir).resolve()
    output_dir.mkdir(parents=True, exist_ok=True)

    if not input_path.exists():
        print(f"[remove] 错误: 找不到输入文件 {input_path}", file=sys.stderr)
        return 1

    iccids = load_iccids(input_path)
    if not iccids:
        print("[remove] 错误: CSV 中没有找到有效的 ICCID", file=sys.stderr)
        return 1

    print(f"[remove] 读取到 {len(iccids)} 个 ICCID，开始生成 SQL...")

    generated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    db_sql_path = output_dir / "remove_cards_db.sql"
    redis_sql_path = output_dir / "remove_cards_redis_gen.sql"

    db_sql_path.write_text(generate_db_sql(iccids, generated_at), encoding="utf-8")
    redis_sql_path.write_text(generate_redis_gen_sql(iccids, generated_at), encoding="utf-8")

    print(f"[remove] 生成完成:")
    print(f"  数据库删除 SQL : {db_sql_path}")
    print(f"  Redis 清理 SQL : {redis_sql_path}")
    print()
    print("执行步骤:")
    print("  1. 先执行 Redis 清理（在删除卡数据之前，以便 SQL 还能查到卡 ID）:")
    print(f"     psql <连接参数> -t -A -f {redis_sql_path} | redis-cli")
    print("  2. 再执行数据库删除:")
    print(f"     psql <连接参数> -1 -f {db_sql_path}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
