-- 160_insight_rules.sql — Insight Engine (Sprint 8, WP-8B)
-- Kontrak Sprint 8 §Insight Engine · Blueprint §5d (rule engine deterministik 4 lapis).
--
-- ============================================================================
-- PRINSIP: "konfigurasi adalah data". Menambah insight = INSERT satu baris di sini
-- (atau langsung di database) — TANPA ubah kode, TANPA deploy, TANPA restart.
-- App\Service\InsightService membaca ulang insight_rule + insight_playbook pada
-- SETIAP permintaan /api/bva.
-- ============================================================================
--
-- IDEMPOTENSI (ADR-010): file ini BOOTSTRAP-ONLY.
--   · insight_rule   -> INSERT IGNORE (unik rule_code)
--   · insight_playbook -> INSERT ... SELECT ... WHERE NOT EXISTS (kunci: rule + sort_order)
--   · param_global   -> INSERT ... SELECT ... WHERE NOT EXISTS
-- Re-run seed TIDAK PERNAH menimpa rule/ambang yang sudah disetel hidup oleh admin.
-- Ingin mengubah rule bawaan: UPDATE manual, bukan edit file ini lalu re-seed.
--
-- ============================================================================
-- DSL condition_expr / impact_expr / placeholder template
-- ============================================================================
-- Dievaluasi App\Insight\ExprEvaluator: tokenizer + parser + interpreter sendiri.
-- TIDAK ADA eval() PHP. Yang diizinkan HANYA:
--   operator : + - * / %  == != <> < <= > >=  and(&&) or(||) not(!)  ( ) ,
--   fungsi   : abs min max round floor ceil sqrt pow if coalesce
--   literal  : angka, string berkutip, true, false, null
--   variabel : WAJIB berawalan acct. / agg. / ftr. / param.  (nama lain = rule ditolak
--              saat parse dan dicatat di meta.errors respons — rule cacat tidak
--              menjatuhkan endpoint)
--
-- SCOPE ditentukan otomatis dari condition_expr:
--   memakai acct.* -> rule diuji PER BARIS AKUN terfilter
--   tanpa  acct.*  -> rule diuji SEKALI atas agregat filter
--
-- Variabel tersedia (lihat docblock InsightService untuk daftar lengkap):
--   ftr.   year months_n months_elapsed month_lock month_min month_max rows_n
--   agg.   rev_b rev_a rev_all_b rev_all_a hpp_b hpp_a exp_b exp_a gop_b gop_a
--          rev_var hpp_var exp_var gop_var hpp_pct_a hpp_pct_b exp_pct_a
--          capai_rev capai_gop pace adverse_total favorable_total
--   acct.  code name divisi kategori is_revenue b a var favvar absvar pct_var
--          rank_adverse rank_favorable streak_over months_over months_n share_rev
--   param. seluruh param_global, kode di-LOWERCASE (HPP_TARGET_PCT -> param.hpp_target_pct)
--
-- favVar (Kontrak §Dimensi): pendapatan (kategori 1/6) = actual - budget;
-- kategori lain = budget - actual. favVar NEGATIF selalu berarti MERUGIKAN.
--
-- Placeholder narasi: {{ ekspresi | format }}  (format: rp rp2 mld jt num num1 num2
-- int pct pct0 pct2 txt; tanpa format = angka dengan pemisah ribuan id-ID).
--
-- PRIORITAS panel = |dampak| x severity, ambil top 5. severity: 3 tinggi, 2 sedang, 1 info.
-- Dampak sebuah insight = impact_expr playbook ber-sort_order terkecil.
--
-- ============================================================================
-- CONTOH menambah rule baru TANPA deploy (pola yang diuji di
-- tests/wp8b_insight_test.php butir E):
--
--   INSERT INTO insight_rule (rule_code, title, condition_expr, severity, template_text)
--   VALUES ('PAYROLL_RATIO', 'Rasio payroll di atas ambang',
--           'agg.rev_a > 0 and agg.exp_pct_a > 0.35', 2,
--           'Beban usaha {{agg.exp_pct_a|pct}} dari pendapatan.');
--   INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
--   SELECT id, 'Tinjau struktur beban', 'Turunkan ke 35 persen.',
--          '(agg.exp_pct_a - 0.35) * agg.rev_a', 1
--     FROM insight_rule WHERE rule_code = 'PAYROLL_RATIO';
-- ============================================================================


-- ---------------------------------------------------------------------------
-- Parameter: target HPP (Kontrak Sprint 8 §Insight Engine — default 0,32)
-- Dipakai rule HPP_RATIO sebagai param.hpp_target_pct. Nilai boleh diubah admin
-- lewat Admin > Parameter; seed ulang TIDAK menimpanya.
-- ---------------------------------------------------------------------------
INSERT INTO param_global (version_id, param_code, param_value)
SELECT NULL, 'HPP_TARGET_PCT', 0.320000 FROM DUAL
 WHERE NOT EXISTS (
       SELECT 1 FROM param_global WHERE version_id IS NULL AND param_code = 'HPP_TARGET_PCT');


-- ---------------------------------------------------------------------------
-- RULES
-- ---------------------------------------------------------------------------
INSERT IGNORE INTO insight_rule (rule_code, title, condition_expr, severity, template_text) VALUES

-- 1. TOP_ADVERSE — akun dengan favVar terburuk pada filter aktif (Blueprint §5d contoh 1).
('TOP_ADVERSE',
 'Perhatian utama: {{acct.name}}',
 'acct.favvar < 0 and acct.rank_adverse <= 1',
 3,
 '{{acct.name}} ({{acct.divisi}}) meleset {{abs(acct.favvar)|rp}} dari budget — kontributor adverse terbesar pada filter aktif, setara {{abs(acct.pct_var)|pct}} dari pagunya.'),

-- 2. TOP_FAVORABLE — akun dengan favVar terbaik.
('TOP_FAVORABLE',
 'Efisiensi terbesar: {{acct.name}}',
 'acct.favvar > 0 and acct.rank_favorable <= 1',
 1,
 '{{acct.name}} ({{acct.divisi}}) lebih baik {{acct.favvar|rp}} dari budget — kontributor favorable terbesar pada filter aktif.'),

-- 3. HPP_RATIO — HPP% aktual melewati target + 2 poin (param HPP_TARGET_PCT).
('HPP_RATIO',
 'HPP di atas target',
 'agg.rev_a > 0 and agg.hpp_pct_a > param.hpp_target_pct + 0.02',
 3,
 'HPP mencapai {{agg.hpp_pct_a|pct}} dari pendapatan, di atas target {{param.hpp_target_pct|pct}}. Selisih {{agg.hpp_pct_a - param.hpp_target_pct|pct}} poin setara {{(agg.hpp_pct_a - param.hpp_target_pct) * agg.rev_a|rp}}.'),

-- 4. STREAK_OVER — akun melebihi budget 3 bulan berturut-turut di dalam filter.
('STREAK_OVER',
 'Pola berulang: {{acct.name}}',
 'acct.streak_over >= 3',
 2,
 '{{acct.name}} ({{acct.divisi}}) merugikan {{acct.streak_over|int}} bulan berturut-turut ({{acct.months_over|int}} dari {{acct.months_n|int}} bulan terfilter) — pola berulang, bukan kejadian sekali. Akumulasi selisih {{abs(acct.favvar)|rp}}.'),

-- 5. PACE_BEHIND — capai pendapatan tertinggal dari pro-rata bulan tutup buku.
('PACE_BEHIND',
 'Pendapatan tertinggal dari pace',
 'agg.rev_b > 0 and ftr.months_elapsed > 0 and agg.capai_rev < agg.pace - 0.05',
 3,
 'Capai pendapatan {{agg.capai_rev|pct}} sementara pro-rata bulan terkunci {{agg.pace|pct}} ({{ftr.months_elapsed|int}} dari {{ftr.months_n|int}} bulan) — tertinggal {{agg.rev_b * agg.pace - agg.rev_a|rp}}.'),

-- 6. GOP_ADVERSE — laba kotor operasional di bawah budget pada filter aktif.
('GOP_ADVERSE',
 'GOP di bawah budget',
 'agg.gop_b > 0 and agg.gop_a < agg.gop_b',
 2,
 'GOP {{agg.gop_a|rp}} di bawah budget {{agg.gop_b|rp}} — selisih {{agg.gop_b - agg.gop_a|rp}}, tercapai {{agg.capai_gop|pct}}.');


-- ---------------------------------------------------------------------------
-- PLAYBOOK REKOMENDASI (Blueprint §5d lapis [4]: tindakan + rumus dampak rupiah)
-- Dampak insight = playbook sort_order terkecil.
-- ---------------------------------------------------------------------------

-- TOP_ADVERSE
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Kunci pagu {{acct.name}}',
       'Audit rincian akun {{acct.code}} {{acct.name}} di divisi {{acct.divisi}}: cek harga satuan, volume, dan pos ganda. Tetapkan pagu bulanan untuk sisa periode dan syaratkan persetujuan kepala divisi di atas pagu. Potensi koreksi {{abs(acct.favvar)|rp}}.',
       'abs(acct.favvar)', 1
  FROM insight_rule r
 WHERE r.rule_code = 'TOP_ADVERSE'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);

INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Negosiasi ulang pemasok {{acct.divisi}}',
       'Kumpulkan minimal 3 penawaran untuk komponen terbesar {{acct.name}} dan kunci harga untuk sisa periode. Target penghematan 10 persen dari selisih berjalan.',
       'abs(acct.favvar) * 0.10', 2
  FROM insight_rule r
 WHERE r.rule_code = 'TOP_ADVERSE'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 2);

-- TOP_FAVORABLE
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Kunci praktik baik {{acct.divisi}}',
       'Dokumentasikan penyebab efisiensi pada {{acct.code}} {{acct.name}} lalu terapkan ke divisi lain. Jadikan dasar revisi budget periode berikutnya sebesar {{acct.favvar|rp}}.',
       'acct.favvar', 1
  FROM insight_rule r
 WHERE r.rule_code = 'TOP_FAVORABLE'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);

-- HPP_RATIO
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Turunkan HPP ke target {{param.hpp_target_pct|pct}}',
       'Setiap 1 poin HPP setara {{agg.rev_a * 0.01|rp}} pada pendapatan berjalan. Tinjau porsi/resep, susut bahan, dan harga beli 10 item HPP terbesar. Menutup selisih ke target bernilai {{(agg.hpp_pct_a - param.hpp_target_pct) * agg.rev_a|rp}}.',
       '(agg.hpp_pct_a - param.hpp_target_pct) * agg.rev_a', 1
  FROM insight_rule r
 WHERE r.rule_code = 'HPP_RATIO'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);

-- STREAK_OVER
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Revisi pagu bulanan {{acct.name}}',
       'Pola beruntun {{acct.streak_over|int}} bulan menandakan asumsi budget tidak realistis atau kebocoran berulang. Tetapkan sebab akar dalam satu siklus, lalu revisi pagu atau perbaiki proses. Nilai terpapar {{abs(acct.favvar)|rp}}.',
       'abs(acct.favvar)', 1
  FROM insight_rule r
 WHERE r.rule_code = 'STREAK_OVER'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);

-- PACE_BEHIND
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Kejar kekurangan pendapatan',
       'Aktifkan paket promo pada segmen dengan konversi tertinggi dan dorong penjualan langsung. Kekurangan terhadap pro-rata sebesar {{agg.rev_b * agg.pace - agg.rev_a|rp}} harus dikejar pada sisa periode.',
       'agg.rev_b * agg.pace - agg.rev_a', 1
  FROM insight_rule r
 WHERE r.rule_code = 'PACE_BEHIND'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);

-- GOP_ADVERSE
INSERT INTO insight_playbook (rule_id, title, action_text, impact_expr, sort_order)
SELECT r.id,
       'Tutup selisih GOP {{agg.gop_b - agg.gop_a|rp}}',
       'Selisih GOP berasal dari sisi pendapatan {{agg.rev_var|rp}} dan sisi beban {{agg.hpp_var + agg.exp_var|rp}}. Prioritaskan sisi dengan kontribusi terbesar sebelum menambah pagu baru.',
       'agg.gop_b - agg.gop_a', 1
  FROM insight_rule r
 WHERE r.rule_code = 'GOP_ADVERSE'
   AND NOT EXISTS (SELECT 1 FROM insight_playbook p WHERE p.rule_id = r.id AND p.sort_order = 1);
