import http from 'k6/http';
import { check } from 'k6';

// RTGS 부하 스크립트 - pacs.008(ISO 20022, pacs.008.001.08) 실시간 생성 -> Chanel 접수.
// 참가기관(Dbtr/Cdtr Agent MmbId) 무작위 선정, 이체금액 1~200원(개요/PoC 기준).
// 프로세스 (0) 사전확인(개인계좌 잔액/수신계좌)은 참가기관 몫이므로 여기(부하생성기=송신기관)가 담당.
//
// ※ Chanel은 pacs.008.001.08 XSD로 원전문을 검증한다. 반드시 정식 <Document> 구조여야
//    접수(TxSts=RCVD)된다. 구식 <RtgsPacs008> 간이 포맷은 XSD 검증 실패로 RJCT.
//    핵심 추출 필드: EndToEndId(BMI), DbtrAgt/CdtrAgt MmbId(송/수신), Dbtr/CdtrAcct Othr Id, IntrBkSttlmAmt.
//
// 실행 예:
//   steady : k6 run -e RATE=50 -e DURATION=20s loadtest/pacs008.k6.js
//   spike  : k6 run -e MODE=spike loadtest/pacs008.k6.js
//   대시보드: k6 run --out influxdb=http://localhost:8096/k6 ... (관측 프로필)

const BASE = __ENV.CHANEL || 'http://localhost:8091';
const DATE = __ENV.BIZDATE || '20260709';
const ORGS = ['1001','1002','1003','1004','1005','1006','1007','1008','1009','1010',
              '1011','1012','1013','1014','1015','1016','1017','1018','1019'];

function scenarios() {
  if (__ENV.MODE === 'spike') {
    // 스파이크(peak) 산정: 도착률을 단계적으로 올려 최대 접수 처리건수 측정(리뷰어2 B).
    return {
      spike: {
        executor: 'ramping-arrival-rate',
        startRate: Number(__ENV.START || 100),
        timeUnit: '1s',
        preAllocatedVUs: 100, maxVUs: 2000,
        stages: [
          { target: Number(__ENV.PEAK || 1000), duration: __ENV.RAMP || '30s' },
          { target: Number(__ENV.PEAK || 1000), duration: '20s' },
          { target: 0, duration: '10s' },
        ],
      },
    };
  }
  return {
    steady: {
      executor: 'constant-arrival-rate',
      rate: Number(__ENV.RATE || 50),
      timeUnit: '1s',
      duration: __ENV.DURATION || '20s',
      preAllocatedVUs: 50, maxVUs: 500,
    },
  };
}

export const options = { scenarios: scenarios() };

function pad(n, len) { return String(n).padStart(len, '0'); }

export default function () {
  const s = ORGS[Math.floor(Math.random() * ORGS.length)];
  let r = ORGS[Math.floor(Math.random() * ORGS.length)];
  while (r === s) r = ORGS[Math.floor(Math.random() * ORGS.length)];

  const amount = 1 + Math.floor(Math.random() * 200);
  const serial = pad((__VU * 1000000 + __ITER) % 10000000000, 10);
  const bmi = DATE + s + serial;                      // 22자리 EndToEndId = 8+4+10
  const creDtTm = new Date().toISOString().slice(0, 19);   // pacs.008 ISODateTime (초 단위, TZ 생략)

  // pacs.008.001.08 정식 전문 (요소 순서는 XSD 시퀀스 준수 - 정상 샘플과 동일 구조).
  const xml =
    `<?xml version="1.0" encoding="UTF-8"?>` +
    `<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">` +
      `<FIToFICstmrCdtTrf>` +
        `<GrpHdr>` +
          `<MsgId>${bmi}</MsgId>` +
          `<CreDtTm>${creDtTm}</CreDtTm>` +
          `<NbOfTxs>1</NbOfTxs>` +
          `<SttlmInf><SttlmMtd>CLRG</SttlmMtd></SttlmInf>` +
        `</GrpHdr>` +
        `<CdtTrfTxInf>` +
          `<PmtId><EndToEndId>${bmi}</EndToEndId></PmtId>` +
          `<IntrBkSttlmAmt Ccy="KRW">${amount}</IntrBkSttlmAmt>` +
          `<ChrgBr>SLEV</ChrgBr>` +
          `<Dbtr><Nm>BANK-${s}</Nm></Dbtr>` +
          `<DbtrAcct><Id><Othr><Id>ACC-${s}</Id></Othr></Id></DbtrAcct>` +
          `<DbtrAgt><FinInstnId><ClrSysMmbId><MmbId>${s}</MmbId></ClrSysMmbId></FinInstnId></DbtrAgt>` +
          `<CdtrAgt><FinInstnId><ClrSysMmbId><MmbId>${r}</MmbId></ClrSysMmbId></FinInstnId></CdtrAgt>` +
          `<Cdtr><Nm>BANK-${r}</Nm></Cdtr>` +
          `<CdtrAcct><Id><Othr><Id>ACC-${r}</Id></Othr></Id></CdtrAcct>` +
        `</CdtTrfTxInf>` +
      `</FIToFICstmrCdtTrf>` +
    `</Document>`;

  const res = http.post(`${BASE}/pay/customer`, xml, { headers: { 'Content-Type': 'application/xml' } });
  check(res, {
    'status 200': (x) => x.status === 200,
    'accepted (RCVD)': (x) => x.body && x.body.includes('RCVD'),
  });
}
