-- ===========================================================================
-- 97c-security-seed.sql : Wave J 시드 (72-security DDL 이후).
--   토큰볼트·3DS·AVS/CVV·펀딩지시·DCC·채그백수수료·명세서·규제보고 소급 적재.
--   idempotent 가드. 대량 매입 성능 고려하여 최근 구간 위주 + 요약은 전량.
-- ===========================================================================
SELECT setseed(0.51);

-- ---------------------------------------------------------------------------
-- 1. 토큰볼트: 기존 card_limit 의 카드번호를 토큰화 (PAN 원문 미저장).
-- ---------------------------------------------------------------------------
INSERT INTO card_vault (token, pan_masked, pan_hash, bin, last4, card_type, issuer, exp_ym)
SELECT 'TKN-' || substr(md5(cl.card_no), 1, 12),
       substr(cl.card_no,1,4) || '-****-****-' || right(cl.card_no,4),
       encode(sha256(cl.card_no::bytea), 'hex'),
       substr(cl.card_no,1,6), right(cl.card_no,4),
       CASE WHEN (('x'||substr(md5(cl.card_no),1,4))::bit(16)::int) % 3 = 0 THEN 'CHECK' ELSE 'CREDIT' END,
       (ARRAY['BC','KB','SHINHAN','HYUNDAI','SAMSUNG','LOTTE','NH','HANA'])[1 + (('x'||substr(md5(cl.card_no),5,4))::bit(16)::int) % 8],
       to_char(current_date + ((('x'||substr(md5(cl.card_no),9,3))::bit(12)::int % 48)) * interval '1 month','YYYYMM')
FROM card_limit cl
ON CONFLICT (token) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 2. 3DS/SCA: 비대면(EDI/FOREIGN) 매입에 3DS 인증결과 부여 (최근 3개월 구간).
-- ---------------------------------------------------------------------------
INSERT INTO au_3ds (tds_id, purchase_id, version, eci, cavv, ds_trans_id, auth_status, liability)
SELECT nextval('au_3ds_seq'), p.purchase_id, '2.2.0',
       CASE WHEN r < 0.85 THEN '05' WHEN r < 0.95 THEN '06' ELSE '07' END,
       substr(md5(p.purchase_id::text),1,28),
       'DS-' || substr(md5(p.purchase_id::text||'ds'),1,16),
       CASE WHEN r < 0.85 THEN 'Y' WHEN r < 0.93 THEN 'A' WHEN r < 0.97 THEN 'N' ELSE 'U' END,
       CASE WHEN r < 0.93 THEN 'ISSUER' ELSE 'MERCHANT' END
FROM (SELECT purchase_id, random() r FROM purchase
      WHERE channel IN ('EDI','FOREIGN') AND purchase_id < 10000000) p
WHERE NOT EXISTS (SELECT 1 FROM au_3ds t WHERE t.purchase_id = p.purchase_id);

-- ---------------------------------------------------------------------------
-- 3. AVS/CVV 검증 (전 채널, 최근 3개월).
-- ---------------------------------------------------------------------------
INSERT INTO au_verify (vrf_id, purchase_id, avs_code, cvv_code, risk_score, decision)
SELECT nextval('au_verify_seq'), p.purchase_id,
       (ARRAY['Y','Y','Y','A','Z','N','U'])[1 + (p.purchase_id % 7)],
       (ARRAY['M','M','M','M','N','P','U'])[1 + (p.purchase_id % 7)],
       (p.purchase_id * 7919) % 1000,
       CASE WHEN (p.purchase_id * 7919) % 1000 > 900 THEN 'DECLINE'
            WHEN (p.purchase_id * 7919) % 1000 > 750 THEN 'REVIEW' ELSE 'APPROVE' END
FROM purchase p WHERE p.purchase_id < 10000000
  AND NOT EXISTS (SELECT 1 FROM au_verify v WHERE v.purchase_id = p.purchase_id);

-- ---------------------------------------------------------------------------
-- 4. 펀딩 지시 (순액정산→가맹점 지급, 은행 rails). 펀딩건에 1:1.
-- ---------------------------------------------------------------------------
INSERT INTO st_funding_instr (instr_id, merchant_id, biz_date, bank_code, account_no, amount, rail, status, confirmed_at)
SELECT nextval('st_fundinstr_seq'), f.merchant_id, f.biz_date,
       (ARRAY['KB','SHINHAN','HANA','NH','WOORI'])[1 + (('x'||substr(md5(f.merchant_id),1,4))::bit(16)::int) % 5],
       lpad(((('x'||substr(md5(f.merchant_id),5,6))::bit(24)::int))::text,12,'0'),
       f.deposit, 'FIRMBANK',
       CASE WHEN f.deposit <= 0 THEN 'RETURNED' WHEN random() < 0.995 THEN 'CONFIRMED' ELSE 'SENT' END,
       CASE WHEN random() < 0.995 THEN f.biz_date::timestamptz + interval '1 day 14 hours' ELSE NULL END
FROM st_merchant_funding f
WHERE NOT EXISTS (SELECT 1 FROM st_funding_instr i WHERE i.merchant_id=f.merchant_id AND i.biz_date=f.biz_date);

-- return_code 부여(반환건)
UPDATE st_funding_instr SET return_code='R01-계좌불일치'
WHERE status='RETURNED' AND return_code IS NULL;

-- ---------------------------------------------------------------------------
-- 5. DCC (해외카드 매입 = channel FOREIGN 일부). 승인시 환율고정.
-- ---------------------------------------------------------------------------
INSERT INTO ac_dcc (dcc_id, purchase_id, base_ccy, txn_ccy, base_amount, txn_amount, fx_rate, markup_bps, opted_in)
SELECT nextval('ac_dcc_seq'), p.purchase_id, 'KRW',
       (ARRAY['USD','JPY','EUR','CNY'])[1 + (p.purchase_id % 4)],
       p.amount,
       round(p.amount / fx.rate, 2),
       fx.rate, 300, true
FROM purchase p
CROSS JOIN LATERAL (SELECT (ARRAY[1330.0, 8.9, 1440.0, 185.0])[1 + (p.purchase_id % 4)] AS rate) fx
WHERE p.channel='FOREIGN' AND p.purchase_id < 10000000
  AND NOT EXISTS (SELECT 1 FROM ac_dcc d WHERE d.purchase_id = p.purchase_id);

-- ---------------------------------------------------------------------------
-- 6. 채그백 수수료 (기존 분쟁건에 건당 부과) + 분쟁 SLA/fraud 채움.
-- ---------------------------------------------------------------------------
UPDATE ac_dispute SET sla_due = opened_at::date + 45,
       fraud_flag = (reason_code IN ('10.4','4853'))
WHERE sla_due IS NULL;

INSERT INTO st_cb_fee (cbfee_id, dispute_id, merchant_id, fee_amount, stage, billed, biz_date)
SELECT nextval('st_cbfee_seq'), d.dispute_id, d.merchant_id,
       CASE d.stage WHEN 'ARBITRATION' THEN 50000 WHEN 'PRE_ARB' THEN 30000 ELSE 15000 END,
       d.stage, (d.status IN ('LOST','ACCEPTED')), d.opened_at::date
FROM ac_dispute d
WHERE NOT EXISTS (SELECT 1 FROM st_cb_fee f WHERE f.dispute_id = d.dispute_id);

-- ---------------------------------------------------------------------------
-- 7. retrieval request (분쟁 전 단계 조회요청) — 분쟁건의 일부 + 별도 케이스.
-- ---------------------------------------------------------------------------
INSERT INTO ac_retrieval (retr_id, purchase_id, merchant_id, reason, status, sla_due, fulfilled_at)
SELECT nextval('ac_retrieval_seq'), d.purchase_id, d.merchant_id,
       (ARRAY['거래내역요청','매출전표사본','서명확인','상품수령증빙'])[1 + (d.dispute_id % 4)],
       (ARRAY['FULFILLED','FULFILLED','OPEN','EXPIRED'])[1 + (d.dispute_id % 4)],
       d.opened_at::date + 20,
       CASE WHEN d.dispute_id % 4 < 2 THEN d.opened_at::timestamptz + interval '5 days' ELSE NULL END
FROM ac_dispute d
WHERE d.stage IN ('REPRESENT','PRE_ARB','ARBITRATION')
  AND NOT EXISTS (SELECT 1 FROM ac_retrieval r WHERE r.purchase_id = d.purchase_id);

-- ---------------------------------------------------------------------------
-- 8. 가맹점 월 명세서 (전 기간 월별 집계).
-- ---------------------------------------------------------------------------
INSERT INTO rp_merchant_stmt (stmt_id, merchant_id, stmt_month, gross_sales, txn_count,
       total_fees, interchange, scheme_fee, markup, cb_fees, net_deposit)
SELECT nextval('rp_stmt_seq'), s.merchant_id, s.mth,
       s.gross, s.cnt, s.fees, s.ic, s.sf, s.mk,
       coalesce(cf.cbf,0),
       s.gross - s.fees - coalesce(cf.cbf,0)
FROM (
  SELECT p.merchant_id, to_char(p.biz_date,'YYYYMM') mth,
         sum(CASE WHEN p.status='S' THEN p.amount ELSE 0 END) gross, count(*) cnt,
         coalesce(sum(fc.mdr_total),0) fees, coalesce(sum(fc.interchange),0) ic,
         coalesce(sum(fc.scheme_fee),0) sf, coalesce(sum(fc.markup),0) mk
  FROM purchase p LEFT JOIN st_fee_component fc ON fc.purchase_id=p.purchase_id
  GROUP BY p.merchant_id, to_char(p.biz_date,'YYYYMM')
) s
LEFT JOIN (
  SELECT merchant_id, to_char(biz_date,'YYYYMM') mth, sum(fee_amount) cbf
  FROM st_cb_fee GROUP BY merchant_id, to_char(biz_date,'YYYYMM')
) cf ON cf.merchant_id=s.merchant_id AND cf.mth=s.mth
WHERE s.gross > 0
ON CONFLICT (merchant_id, stmt_month) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 9. 규제보고 (여신전문금융업법: 정산주기 준수·수수료 공시·거래량).
-- ---------------------------------------------------------------------------
INSERT INTO rp_regulatory (reg_id, report_type, period, metric, value, compliant, note)
SELECT nextval('rp_reg_seq'), 'SETTLE_CYCLE', to_char(biz_date,'YYYYMM'),
       '평균정산일수(D+n)', round(avg((settled_at::date - biz_date)),2),
       (avg((settled_at::date - biz_date)) <= 3), '여전법 정산주기 준수(≤3영업일)'
FROM settlement GROUP BY to_char(biz_date,'YYYYMM')
ON CONFLICT DO NOTHING;

INSERT INTO rp_regulatory (reg_id, report_type, period, metric, value, compliant, note)
SELECT nextval('rp_reg_seq'), 'TXN_VOLUME', to_char(biz_date,'YYYYMM'),
       '월 매입건수', count(*), true, '거래량 보고'
FROM purchase GROUP BY to_char(biz_date,'YYYYMM')
ON CONFLICT DO NOTHING;
