# Redis connection + push config cho pack360_v2
# Dùng bởi: scripts/_shared/push_redis_sample.py (và sau này push full)

connection:
  host: "103.67.185.124"
  port: 8379
  database: 1
  username: "redis"
  password: "098poiA"
  socket_timeout: 15
  socket_connect_timeout: 10

push:
  # Key pattern: <key_prefix>:<msisdn>
  # KHÁC v1's `pack360:rec` → không đụng key cũ
  key_prefix: "pack360:profile"

  # TTL (giây). 0 hoặc null = không set TTL (persistent).
  ttl: 0

  # Pipeline batching
  pipe_batch: 200
  batch_delay: 0.0          # giây giữa batches, 0 = không delay

sample:
  # Sample mode: 'stratified' | 'random' | 'vip_only'
  mode: "stratified"
  n_per_group: 250          # stratified: số sub/group A/B/C/D (4×250 = 1000)
  n_total: 1000             # random/vip_only: tổng số

source:
  parquet: "data/output/redis/subscriber_profile.parquet"

# Lọc gói KHÔNG đẩy vào pack_offer_list (build_profile.py đọc).
# Áp dụng tại step 2a — filter rec_code NOT IN list trước khi pivot.
# Tier_count tự giảm + CONCAT_WS skip NULL → list gọn không khoảng trống.
filters:
  exclude_codes:
    - PT70
    - 3PT70
    - 6PT70
    - 12PT70
    - CK30

# Giá trị cố định cho 1 số field (build_profile.py đọc)
defaults:
  weekly_pack: "MBF30"      # cố định cho TẤT CẢ sub (K90/CK30 đã bị exclude)
  voice_pack_list: "K90"    # cố định cho TẤT CẢ sub (gói thoại chuyên 90K, 10,089 phút)

# Affordability cap cho pack_offer_list:
# cap_price = max(arpu_smoothed × multiplier, min_floor)
# Sub có arpu=0 → cap=50K (chỉ MBF30/PT50 trial). Sub arpu=200K → cap=300K.
affordability:
  multiplier: 1.3               # Stretch 30%: cho phép pitch gói cao hơn arpu chút (nhiều ưu đãi hơn)
  min_floor: 50000              # Floor 50K cho sub no-topup → MBF30 vẫn qualify
  sweet_spot_ratio: 0.95        # Pack price ≤ 0.95×arpu được score bonus
  sweet_spot_bonus: 10.0        # Bonus score cho sweet-spot pack
  # Value-upgrade bonus: pack price trong [arpu, arpu × 1.3] + có data/voice nhiều hơn → bonus
  upgrade_zone_bonus: 6.0
  # Fallback nếu sau filter sub không còn gói nào passes affordability cap.
  # MBF30 (30K) là gói rẻ nhất trong catalog → safe default cho dormant sub.
  fallback_code: "MBF30"

# Fields được đẩy vào HASH (10 fields — gọn nhất)
# pack_offer_list = csv top-5 gói theo priority rank (vd "C99N,KC90,NA90,KC70,NA70")
#   App muốn best_value → split(',')[0]. KHÔNG cần best_value_pack riêng.
# voice_pack_list = cố định "K90" cho mọi sub (gói thoại chuyên)
# weekly_pack = "MBF30" cố định cho mọi sub
# sub_segment = winback_A0/A2/A3/A4/A_FRESH | downgrade_B1..B4 | acquisition_C1..C5 | short_cycle_D1a..D3c
# prefers_voice / is_super_vip = "true"/"false" string
# Đã BỎ: best_value_pack/_price (redundant với pack_offer_list[0]), tier_X_*,
#        current_pack_price (cứng 0), tier_count (split list tự đếm), _group (diagnostic only)
hash_fields:
  - pack_offer_list
  - voice_pack_list
  - weekly_pack
  - current_pack
  - current_pack_type
  - sub_segment
  - prefers_voice
  - is_super_vip
  - arpu_avg
  - _updated_at
