-- ===========================================================================
-- 96-econ-seed.sql : 매입사 경제모델 시드 (70-econ.sql DDL 이후, 실측풍)
--   요율표(interchange/scheme) + 회원사 은행 + 기존 정산건 소급 분해/클리어링/
--   순액정산/펀딩. 규제 관행 반영: interchange 가 MDR 의 대부분(70~90%),
--   scheme fee 소액, markup 이 매입사 협상마진.
-- ===========================================================================

-- ---------------------------------------------------------------------------
-- 1. Interchange 요율표 — 카드종류×채널 차등 (interchange qualification)
--    실제 규제 관행: 체크카드 < 신용카드, 대면(POS) < 비대면(EDI)/해외(FOREIGN).
-- ---------------------------------------------------------------------------
INSERT INTO st_interchange_rate (card_type, mcc, channel, txn_type, rate_bps, fixed_fee) VALUES
 ('CREDIT','DEFAULT','POS','SALE',     130, 0),
 ('CREDIT','DEFAULT','EDC','SALE',     140, 0),
 ('CREDIT','DEFAULT','EDI','SALE',     160, 0),   -- 비대면 가산
 ('CREDIT','DEFAULT','FOREIGN','SALE', 180, 0),   -- 해외 가산
 ('CHECK','DEFAULT','POS','SALE',       70, 0),   -- 체크카드 저율
 ('CHECK','DEFAULT','EDC','SALE',       80, 0),
 ('CHECK','DEFAULT','EDI','SALE',       95, 0),
 ('CHECK','DEFAULT','FOREIGN','SALE',  110, 0),
 ('PREPAID','DEFAULT','POS','SALE',     60, 0),
 ('CREDIT','DEFAULT','DEFAULT','REFUND',  0, 0),  -- 환불은 interchange 역방향(발급사→매입사), 여기선 0 처리
 ('CREDIT','DEFAULT','DEFAULT','CASH',  100, 0)
ON CONFLICT (card_type, mcc, channel, txn_type) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 2. Scheme fee — 스킴 assessment (소액). BC=국내 표준.
-- ---------------------------------------------------------------------------
INSERT INTO st_scheme_fee (scheme, txn_type, rate_bps, fixed_fee) VALUES
 ('BC','SALE',    11, 0),
 ('VISA','SALE',  14, 0),
 ('MASTER','SALE',13, 0),
 ('LOCAL','SALE',  9, 0),
 ('BC','REFUND',   0, 0),
 ('BC','CASH',     8, 0)
ON CONFLICT (scheme, txn_type) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 3. 회원사 은행 — 발급사↔매입사 다자 순액정산 참가자 (BC카드 컨소시엄형).
-- ---------------------------------------------------------------------------
INSERT INTO st_member_bank (bank_code, bank_name, bin, role) VALUES
 ('BC',     'BC카드(매입)',     '940020','ACQUIRER'),
 ('KB',     'KB국민카드',       '940021','ISSUER'),
 ('SHINHAN','신한카드',         '940022','ISSUER'),
 ('HYUNDAI','현대카드',         '940023','ISSUER'),
 ('SAMSUNG','삼성카드',         '940024','ISSUER'),
 ('LOTTE',  '롯데카드',         '940025','ISSUER'),
 ('NH',     'NH농협카드',       '940026','ISSUER'),
 ('HANA',   '하나카드',         '940027','ISSUER')
ON CONFLICT (bank_code) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 4. 기존 정산완료 매입건 → 수수료 3층 분해 (소급).
--    카드종류는 issuer 로 근사(BC=CHECK 30%, 그 외 CREDIT), 채널=purchase.channel.
--    interchange = amount×ic_bps, scheme = amount×scheme_bps,
--    markup = 기존 flat fee − interchange − scheme (음수면 0 clamp),
--    mdr_total = interchange+scheme+markup (기존 fee 와 근사 일치).
-- ---------------------------------------------------------------------------
INSERT INTO st_fee_component (purchase_id, amount, interchange, scheme_fee, markup, mdr_total, card_type, scheme)
SELECT p.purchase_id, p.amount,
       (p.amount * ic.rate_bps / 10000)                                  AS interchange,
       (p.amount * sf.rate_bps / 10000)                                  AS scheme_fee,
       GREATEST(p.fee - (p.amount*ic.rate_bps/10000) - (p.amount*sf.rate_bps/10000), p.amount*8/10000) AS markup,
       (p.amount*ic.rate_bps/10000) + (p.amount*sf.rate_bps/10000)
         + GREATEST(p.fee - (p.amount*ic.rate_bps/10000) - (p.amount*sf.rate_bps/10000), p.amount*8/10000) AS mdr_total,
       ct.card_type,
       CASE WHEN p.issuer IN ('BC') THEN 'BC' ELSE 'BC' END              AS scheme
FROM purchase p
CROSS JOIN LATERAL (SELECT CASE WHEN (p.purchase_id % 10) < 3 THEN 'CHECK' ELSE 'CREDIT' END AS card_type) ct
JOIN st_interchange_rate ic
     ON ic.card_type = ct.card_type AND ic.channel = p.channel AND ic.txn_type = 'SALE'
JOIN st_scheme_fee sf ON sf.scheme = 'BC' AND sf.txn_type = 'SALE'
WHERE p.status = 'S'
ON CONFLICT (purchase_id) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 5. 프레젠트먼트(클리어링) — 정산완료건마다 1차 프레젠트먼트 기록.
--    clearing_amt = amount − interchange (발급사 귀속분 차감 후 매입사 클리어링액).
-- ---------------------------------------------------------------------------
INSERT INTO cl_presentment (presentment_id, purchase_id, scheme, msg_class, clearing_amt, present_date, cycle, status)
SELECT nextval('cl_present_seq'), fc.purchase_id, fc.scheme, 'FIRST_PRESENT',
       fc.amount - fc.interchange, p.biz_date, 'T+1', 'CLEARED'
FROM st_fee_component fc JOIN purchase p ON p.purchase_id = fc.purchase_id
WHERE NOT EXISTS (SELECT 1 FROM cl_presentment c
                  WHERE c.purchase_id = fc.purchase_id AND c.msg_class = 'FIRST_PRESENT');

-- ---------------------------------------------------------------------------
-- 6. 순액정산 배치 — 발급사(회원 BIN)×영업일 기준 차대변 합산 → 단일 순액.
--    매입사(BC)가 각 발급사로부터 (매출−interchange−scheme) 순액을 수취.
-- ---------------------------------------------------------------------------
INSERT INTO st_net_settlement (net_id, scheme, member_bin, biz_date, txn_count,
       gross_amt, interchange_amt, scheme_fee_amt, net_amt, direction, status)
SELECT nextval('st_netset_seq'), 'BC', mb.bin, p.biz_date, count(*),
       sum(fc.amount), sum(fc.interchange), sum(fc.scheme_fee),
       sum(fc.amount - fc.interchange - fc.scheme_fee), 'RECEIVE', 'SETTLED'
FROM st_fee_component fc
JOIN purchase p ON p.purchase_id = fc.purchase_id
JOIN st_member_bank mb ON mb.bank_code = p.issuer
GROUP BY mb.bin, p.biz_date
ON CONFLICT (scheme, member_bin, biz_date) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 7. 롤링 리저브 — 위험업종(HOLD/PENDING 상태였던 가맹점 등) 8% 유보, 그 외 0.
--    여기선 전 가맹점 일괄 저율(총매출의 0.5%) 유보 예시 + T+30 해제.
-- ---------------------------------------------------------------------------
INSERT INTO st_reserve (merchant_id, biz_date, reserve_bps, reserve_amt, release_date, released)
SELECT p.merchant_id, p.biz_date, 50, sum(p.amount)*50/10000,
       p.biz_date + 30, (p.biz_date + 30 < current_date)
FROM purchase p WHERE p.status='S'
GROUP BY p.merchant_id, p.biz_date
ON CONFLICT (merchant_id, biz_date) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 8. 가맹점 펀딩 항등식: 총매출 − 환불 − 채그백 − 수수료 − 리저브 = 입금.
--    환불=취소(C)건 금액, 채그백=아래 8단계 시드분, 수수료=MDR합계.
-- ---------------------------------------------------------------------------
INSERT INTO st_merchant_funding (funding_id, merchant_id, biz_date, gross_sales, refunds,
       chargebacks, fees, reserve, deposit, funding_model, status)
SELECT nextval('st_funding_seq'), s.merchant_id, s.biz_date,
       s.gross, s.refunds, s.cb, s.fees, coalesce(rv.reserve_amt,0),
       s.gross - s.refunds - s.cb - s.fees - coalesce(rv.reserve_amt,0),
       'NET_DAILY', 'FUNDED'
FROM (
  SELECT p.merchant_id, p.biz_date,
         sum(CASE WHEN p.status='S' THEN p.amount ELSE 0 END) AS gross,
         sum(CASE WHEN p.status='C' THEN p.amount ELSE 0 END) AS refunds,
         0::bigint AS cb,
         coalesce(sum(fc.mdr_total),0) AS fees
  FROM purchase p LEFT JOIN st_fee_component fc ON fc.purchase_id=p.purchase_id
  GROUP BY p.merchant_id, p.biz_date
) s
LEFT JOIN st_reserve rv ON rv.merchant_id=s.merchant_id AND rv.biz_date=s.biz_date
WHERE s.gross > 0
ON CONFLICT (merchant_id, biz_date) DO NOTHING;

-- ---------------------------------------------------------------------------
-- 9. 채그백/분쟁 케이스 — 취소·보류였던 매입 일부를 분쟁으로 (reason code 체계).
--    라이프사이클 단계 혼재: FIRST_CB / REPRESENT / PRE_ARB / ARBITRATION.
-- ---------------------------------------------------------------------------
INSERT INTO ac_dispute (dispute_id, purchase_id, merchant_id, reason_code, amount, stage, status, opened_at, resolved_at, memo)
SELECT nextval('ac_dispute_seq'), p.purchase_id, p.merchant_id,
       (ARRAY['10.4','13.1','12.6','13.7','4853'])[1 + (p.purchase_id % 5)],
       p.amount,
       (ARRAY['FIRST_CB','REPRESENT','PRE_ARB','ARBITRATION'])[1 + (p.purchase_id % 4)],
       (ARRAY['OPEN','WON','LOST','ACCEPTED'])[1 + (p.purchase_id % 4)],
       p.biz_date::timestamptz + interval '2 days',
       CASE WHEN (p.purchase_id % 4) IN (1,2,3) THEN p.biz_date::timestamptz + interval '20 days' ELSE NULL END,
       '분쟁 시드: reason ' || (ARRAY['사기','상품미수취','중복청구','품질불량','거래취소'])[1 + (p.purchase_id % 5)]
FROM purchase p
WHERE p.status IN ('C','H') AND (p.purchase_id % 3) = 0
  AND NOT EXISTS (SELECT 1 FROM ac_dispute d WHERE d.purchase_id = p.purchase_id);

-- 펀딩의 chargebacks 컬럼을 실제 분쟁(LOST 확정분)으로 보정.
-- 채그백은 원매입의 영업일(biz_date)에 귀속시켜 가맹점×일자 단위로만 차감한다
-- (가맹점 전체 합을 매일 중복 차감하면 입금액이 일수만큼 붕괴한다).
UPDATE st_merchant_funding f SET chargebacks = d.cb,
       deposit = f.gross_sales - f.refunds - d.cb - f.fees - f.reserve
FROM (SELECT p.merchant_id, p.biz_date, sum(dp.amount) cb
      FROM ac_dispute dp JOIN purchase p ON p.purchase_id = dp.purchase_id
      WHERE dp.status = 'LOST' GROUP BY p.merchant_id, p.biz_date) d
WHERE f.merchant_id = d.merchant_id AND f.biz_date = d.biz_date;
