/**
 * SBV ISO 20022 — pain.001.001.09 Outbound Builder
 * Xây dựng message CustomerCreditTransferInitiation (pain.001) từ dữ liệu KH.
 *
 * Sử dụng khi:
 *   - NHTM khởi tạo lệnh chuyển khoản qua API JSON → Gateway nhận và emit pain.001
 *   - Migration IBPS pain -> ISO 20022 pain.001 outbound flow
 *
 * Cơ quan chủ quản: Ngân hàng Nhà nước Việt Nam (SBV)
 */

import { Builder } from 'xml2js';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';

// ─── Types ───────────────────────────────────────────────────────────────────

/** Đầu vào từ NHTM hoặc KH gửi qua REST API */
export interface Pain001Input {
  /** Message ID duy nhất (do NHTM tạo, max 35 ký tự) */
  msgId:         string;
  /** Ngày thực hiện lệnh (YYYY-MM-DD) */
  executionDate: string;
  /** BIC tổ chức khởi tạo */
  debtorBic:     string;
  /** Số tài khoản người chuyển */
  debtorAcct:    string;
  /** Tên người chuyển (max 140) */
  debtorName:    string;
  /** BIC ngân hàng thụ hưởng */
  creditorBic:   string;
  /** Số tài khoản người thụ hưởng */
  creditorAcct:  string;
  /** Tên người thụ hưởng (max 140) */
  creditorName:  string;
  /** Số tiền (đơn vị: VND nguyên) */
  amount:        number;
  /** Mã tiền tệ (mặc định: VND) */
  currency?:     string;
  /** Mục đích thanh toán ISO 20022 (SALA, TAXS, GOVT, ...) */
  purposeCode?:  string;
  /** Nội dung chuyển tiền (max 140) */
  remittanceInfo?: string;
  /** Dịch vụ thanh toán: NURG (thông thường), URGP (khẩn) */
  serviceLevel?:   'NURG' | 'URGP' | 'SDVA';
  /** Hệ thống thanh toán nội tuyến: IBPS, MBRIDGE, VNLH */
  localInstrument?:'IBPS' | 'MBRIDGE' | 'VNLH';
}

/** Kết quả build pain.001 */
export interface Pain001Result {
  /** XML message pain.001.001.09 hoàn chỉnh */
  isoXml:         string;
  /** Business Application Header head.001.001.03 */
  businessAppHdr: string;
  /** SHA-256 hash để neo Gov-Chain */
  messageHash:    string;
  /** Unique End-to-end Transaction Reference */
  uetr:           string;
  /** Payment Information ID */
  pmtInfId:       string;
}

// ─── Constants ───────────────────────────────────────────────────────────────

const NS_PAIN001 = 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.09';
const NS_HEAD001 = 'urn:iso:std:iso:20022:tech:xsd:head.001.001.03';
const SBV_BIC    = 'SBVNVNVX';

// ─── Builder ─────────────────────────────────────────────────────────────────

/**
 * Xây dựng pain.001.001.09 từ Pain001Input.
 * Tự động gán:
 *  - UETR mới (UUID v4)
 *  - CreDtTm tại thời điểm gọi hàm (UTC+7)
 *  - Business Application Header (head.001)
 */
export function buildPain001(input: Pain001Input): Pain001Result {
  const uetr      = uuidv4();
  const pmtInfId  = `PMTINF-${input.msgId}`;
  const now       = new Date();
  const creDtTm   = toIsoUtc7(now);
  const ccy       = input.currency ?? 'VND';
  const svcLvl    = input.serviceLevel    ?? 'NURG';
  const lclInstrm = input.localInstrument ?? 'IBPS';

  const pain001 = {
    Document: {
      $: { xmlns: NS_PAIN001 },
      CstmrCdtTrfInitn: {
        GrpHdr: {
          MsgId:   input.msgId,
          CreDtTm: creDtTm,
          NbOfTxs: '1',
          CtrlSum:  input.amount,
          InitgPty: {
            Nm: input.debtorName.slice(0, 140),
          },
        },
        PmtInf: [
          {
            PmtInfId:     pmtInfId,
            PmtMtd:       'TRF',
            NbOfTxs:      '1',
            CtrlSum:       input.amount,
            PmtTpInf: {
              SvcLvl:   { Cd: svcLvl },
              LclInstrm:{ Prtry: lclInstrm },
            },
            ReqdExctnDt:  { Dt: input.executionDate },
            Dbtr: {
              Nm: input.debtorName.slice(0, 140),
              PstlAdr: { Ctry: 'VN' },
            },
            DbtrAcct: { Id: { Othr: { Id: input.debtorAcct } } },
            DbtrAgt:  { FinInstnId: { BICFI: input.debtorBic } },
            CdtTrfTxInf: [
              {
                PmtId: {
                  EndToEndId: input.msgId,
                  UETR:       uetr,
                },
                Amt: {
                  InstdAmt: { _: input.amount.toFixed(2), $: { Ccy: ccy } },
                },
                ...(input.purposeCode ? { Purp: { Cd: input.purposeCode } } : {}),
                ...(input.remittanceInfo ? { RmtInf: { Ustrd: [input.remittanceInfo.slice(0, 140)] } } : {}),
                CdtrAgt:  { FinInstnId: { BICFI: input.creditorBic } },
                Cdtr: {
                  Nm: input.creditorName.slice(0, 140),
                },
                CdtrAcct: { Id: { Othr: { Id: input.creditorAcct } } },
              }
            ],
          }
        ],
      },
    }
  };

  const builder    = new Builder({ xmldec: { version: '1.0', encoding: 'UTF-8' } });
  const isoXml     = builder.buildObject(pain001);
  const msgHash    = createHash('sha256').update(isoXml, 'utf8').digest('hex');
  const appHdr     = buildHead001(input.msgId, creDtTm, NS_PAIN001, input.debtorBic);

  return { isoXml, businessAppHdr: appHdr, messageHash: msgHash, uetr, pmtInfId };
}

// ─── Helpers ─────────────────────────────────────────────────────────────────

/** Chuyển Date → ISO 8601 chuỗi UTC+7 */
function toIsoUtc7(d: Date): string {
  const offset = 7 * 60 * 60 * 1000;
  const local  = new Date(d.getTime() + offset);
  return local.toISOString().replace('Z', '+07:00');
}

/** Tạo Business Application Header head.001.001.03 */
function buildHead001(msgId: string, creDt: string, msgDefId: string, fromBic: string): string {
  const header = {
    AppHdr: {
      $:         { xmlns: NS_HEAD001 },
      Fr:        { FIId: { FinInstnId: { BICFI: fromBic } } },
      To:        { FIId: { FinInstnId: { BICFI: SBV_BIC } } },
      BizMsgIdr: msgId,
      MsgDefIdr: msgDefId,
      CreDt:     creDt,
    }
  };
  return new Builder({ xmldec: { version: '1.0', encoding: 'UTF-8' } }).buildObject(header);
}
