"""
Ch6 配套代码 2 / 3 —— AOF 配置查看 + 重写触发

演示：
  1. CONFIG GET 看 AOF 是否启用、刷盘策略、混合持久化开关等
  2. 写入并删除大量 key 制造冗余命令，观察 AOF 文件膨胀
  3. BGREWRITEAOF 触发重写，通过 INFO persistence 的 aof_rewrite_in_progress
     与 aof_current_size 看到「重写完成 → 文件被压缩」的过程
"""

import time
import redis

r = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True)


def section(title: str) -> None:
    print("\n" + "=" * 60)
    print(title)
    print("=" * 60)


def show_aof_config() -> None:
    section("Demo 1: CONFIG GET —— AOF 相关参数")

    keys = [
        ("appendonly",                   "是否启用 AOF（yes/no）"),
        ("appendfsync",                  "刷盘策略：always / everysec / no"),
        ("appendfilename",               "AOF 文件名（7+ 是 manifest 名）"),
        ("appenddirname",                "AOF 目录名（Redis 7 新增）"),
        ("aof-use-rdb-preamble",         "混合持久化开关"),
        ("auto-aof-rewrite-percentage",  "AOF 增长百分比触发自动重写"),
        ("auto-aof-rewrite-min-size",    "AOF 最小多大才考虑自动重写"),
        ("no-appendfsync-on-rewrite",    "重写期间是否暂停 fsync（避免阻塞）"),
    ]

    print(f"  {'参数':<35} {'当前值':<22} 含义")
    print(f"  {'-'*35} {'-'*22} {'-'*38}")
    for k, desc in keys:
        v = r.config_get(k)
        val = list(v.values())[0] if v else "（不存在）"
        print(f"  {k:<35} {val:<22} {desc}")


def write_then_delete(prefix: str, n: int) -> None:
    pipe = r.pipeline()
    for i in range(n):
        pipe.set(f"{prefix}:{i}", f"v-{i}-{'a' * 30}")
    pipe.execute()
    pipe = r.pipeline()
    for i in range(n):
        pipe.delete(f"{prefix}:{i}")
    pipe.execute()


def demo_trigger_rewrite() -> None:
    section("Demo 2: BGREWRITEAOF —— 把冗余命令压成最小集")

    if r.config_get("appendonly").get("appendonly") != "yes":
        print("  ⚠️ 当前未启用 AOF，临时打开 ...")
        r.config_set("appendonly", "yes")
        time.sleep(0.5)

    info1 = r.info("persistence")
    size_before = info1.get("aof_current_size", 0)
    print(f"  step 1  aof_current_size = {size_before:>10} bytes")

    print("  step 2  写入并删除 3000 个 key（制造 6000 条冗余命令）...")
    write_then_delete("rewrite", 3000)

    info2 = r.info("persistence")
    size_after_write = info2.get("aof_current_size", 0)
    print(f"  step 3  aof_current_size = {size_after_write:>10} bytes  "
          f"(增加了 {size_after_write - size_before})")

    print("  step 4  触发 BGREWRITEAOF ...")
    r.bgrewriteaof()

    for _ in range(40):
        time.sleep(0.5)
        info3 = r.info("persistence")
        if info3.get("aof_rewrite_in_progress", 0) == 0:
            size_final = info3.get("aof_current_size", 0)
            saved = (1 - size_final / max(size_after_write, 1)) * 100
            print(f"  step 5  aof_current_size = {size_final:>10} bytes  "
                  f"(压缩率 {saved:.1f}%)")
            return
    print("  ⚠️ 重写超时未完成，可稍后再 INFO persistence 查看")


def demo_aof_info_fields() -> None:
    section("Demo 3: INFO persistence —— AOF 相关字段")
    info = r.info("persistence")
    fields = [
        ("aof_enabled",                  "AOF 是否启用"),
        ("aof_rewrite_in_progress",      "是否正在重写"),
        ("aof_rewrite_scheduled",        "是否有重写排队"),
        ("aof_last_rewrite_time_sec",    "上次重写耗时（秒）"),
        ("aof_current_rewrite_time_sec", "当前重写已运行秒数"),
        ("aof_last_bgrewrite_status",    "上次重写状态"),
        ("aof_last_write_status",        "上次 write 是否成功"),
        ("aof_last_cow_size",            "上次重写 COW 占用字节"),
        ("aof_current_size",             "当前 AOF 文件大小"),
        ("aof_base_size",                "上次重写后的基准大小"),
        ("aof_buffer_length",            "AOF 缓冲区还未 write 的字节数"),
        ("aof_delayed_fsync",            "因 fsync 慢而被迫等待的次数（关键指标）"),
    ]
    for k, desc in fields:
        v = info.get(k, "N/A")
        print(f"  {k:<32} = {str(v):<14} {desc}")


if __name__ == "__main__":
    try:
        show_aof_config()
        demo_trigger_rewrite()
        demo_aof_info_fields()
    except redis.ConnectionError as e:
        print(f"❌ Redis 连接失败: {e}")
