/*
 * AC_DCC.pgc - ac (매입) 모듈 서비스 AC_DCC (one service = one file).
 * DCC(Dynamic Currency Conversion) 다통화 환산: 해외카드 소지자가 원화가맹점에서
 *   자국통화 결제를 선택할 때, 원화 매입금액을 승인시점 고정환율 + DCC 마크업(3%)
 *   으로 카드소지자 통화(USD/JPY/EUR/CNY)로 환산해 ac_dcc 에 적재한다.
 * 환율(원/외화 1단위): USD 1330, JPY 8.9, EUR 1440, CNY 185 (스케일 x10 정수보관).
 *   txn_amount = base_amount / rate * (1 + markup) — 정수 절삭 없이 NUMERIC 연산.
 * 처리단계: 입력검증 -> 매입 컨텍스트 조회 -> 통화/환율 결정 -> 환산 -> 본처리(INSERT)
 *   -> 감사이력 -> 재검증 -> 응답 -> 로깅.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). ac_svr 가 tpsvrinit 에서 광고.
 */
#include "AC_DCC.h"

/* AC_DCC - DCC 다통화 환산(승인시점 환율고정 + 마크업). */
void AC_DCC(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ---- 지역 스크래치 (DECLARE SECTION 밖에서 초기화) ---- */
    char  ccy[8], msgbuf[220];
    long  rate10 = 0, txn_int = 0, fx_int = 0;

    EXEC SQL BEGIN DECLARE SECTION;
    long  h_pid, h_base, h_rate10, h_markup, h_dcc, h_txn_i, h_orig;
    char  h_ccy[8], h_base_ccy[8], h_bizdate[16], h_status[16], h_svc[24], h_msg[220];
    EXEC SQL END DECLARE SECTION;

    strcpy(h_svc, "AC_DCC");
    h_pid = h_base = h_dcc = h_txn_i = h_orig = 0;
    h_markup = 300; strcpy(h_base_ccy, "KRW"); strcpy(h_status, "CONVERTED");
    strcpy(h_bizdate, "2026-07-19");

    /* ===== 1) 입력 검증부 ===== */
    h_pid = getl(b, T_PURCHASE_ID);
    if (h_pid <= 0) {
        setl(b, T_RC, 8701); Bchg(b, T_MSG, 0, "매입 ID(purchase_id) 필수", 0L);
        userlog("[AC_DCC] 매입 ID 검증 실패 pid=%ld", h_pid); FAIL(b);
    }
    gets_(b, T_STR1, ccy, sizeof(ccy));
    if (ccy[0] == 0) strcpy(ccy, "USD");
    h_base = getl(b, T_AMOUNT);

    /* 통화별 고정환율(스케일 x10): 문자열 비교로 결정(캐스팅 없음). */
    if      (strcmp(ccy, "USD") == 0) rate10 = 13300;
    else if (strcmp(ccy, "JPY") == 0) rate10 = 89;
    else if (strcmp(ccy, "EUR") == 0) rate10 = 14400;
    else if (strcmp(ccy, "CNY") == 0) rate10 = 1850;
    else {
        setl(b, T_RC, 8702); Bchg(b, T_MSG, 0, "지원하지 않는 통화(txn_ccy)", 0L);
        userlog("[AC_DCC] 미지원 통화 ccy=[%s]", ccy); FAIL(b);
    }
    strncpy(h_ccy, ccy, sizeof(h_ccy)-1); h_ccy[sizeof(h_ccy)-1] = 0;
    h_rate10 = rate10;
    userlog("[다통화] DCC 환산 진입 pid=%ld ccy=%s base=%ld rate10=%ld", h_pid, h_ccy, h_base, h_rate10);

    /* ===== 2) 매입 컨텍스트 조회부 (원금/영업일 보정) ===== */
    EXEC SQL SELECT amount, biz_date INTO :h_orig, :h_bizdate FROM purchase WHERE purchase_id = :h_pid;
    if (sqlca.sqlcode == 100) {
        /* 체인/미커밋 매입일 수 있어 실패 처리하지 않는다(RECONCILE 격리 규율). */
        if (h_bizdate[0] == 0) strcpy(h_bizdate, "2026-07-19");
        userlog("[AC_DCC] 매입 미조회 pid=%ld — 전문/기본값으로 진행", h_pid);
    } else if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8710); Bchg(b, T_MSG, 0, "매입 조회 오류", 0L); FAIL(b);
    }
    /* 원화금액 미지정 시 원 매입금액을 환산 대상으로 사용 */
    if (h_base <= 0) h_base = h_orig;
    if (h_base <= 0) {
        setl(b, T_RC, 8703); Bchg(b, T_MSG, 0, "환산 대상 원화 금액 없음", 0L);
        userlog("[AC_DCC] 환산 금액 0 pid=%ld", h_pid); FAIL(b);
    }

    /* ===== 3) 환산부 (외화금액·환율 정수부 산출) ===== */
    /* txn = base/rate*(1+markup) = base*(10000+markup)/(rate10*1000) */
    txn_int = h_base * (10000 + h_markup) / (h_rate10 * 1000);
    fx_int  = h_rate10 / 10;
    userlog("[AC_DCC] 환산 base=%ld ccy=%s rate=%ld.%ld markup=%ld -> txn≈%ld %s",
            h_base, h_ccy, fx_int, h_rate10 % 10, h_markup, txn_int, h_ccy);

    /* ===== 4) 본처리부 (ac_dcc INSERT — NUMERIC 정밀연산) ===== */
    EXEC SQL SELECT nextval('ac_dcc_seq') INTO :h_dcc;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8720); Bchg(b, T_MSG, 0, "DCC 시퀀스 실패", 0L); FAIL(b); }
    EXEC SQL INSERT INTO ac_dcc
        (dcc_id, purchase_id, base_ccy, txn_ccy, base_amount, txn_amount, fx_rate, markup_bps, opted_in)
        VALUES (:h_dcc, :h_pid, :h_base_ccy, :h_ccy, :h_base,
                :h_base * (10000 + :h_markup) / (:h_rate10 * 1000.0),
                :h_rate10 / 10.0, :h_markup, true);
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8721); Bchg(b, T_MSG, 0, "DCC 적재 실패", 0L);
        userlog("[AC_DCC] ac_dcc INSERT 실패 [%d]", sqlca.sqlcode); FAIL(b);
    }

    /* ===== 5) 감사이력 적재부 (cm_log) ===== */
    snprintf(msgbuf, sizeof(msgbuf), "AC_DCC pid=%ld base=%ld KRW -> %ld %s (rate=%ld.%ld markup=%ldbps)",
             h_pid, h_base, txn_int, h_ccy, fx_int, h_rate10 % 10, h_markup);
    strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0;
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8730); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); }

    /* ===== 6) 재검증부 (적재행 외화금액 정수부 재조회) ===== */
    EXEC SQL SELECT floor(txn_amount) INTO :h_txn_i FROM ac_dcc WHERE dcc_id = :h_dcc;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
        setl(b, T_RC, 8740); Bchg(b, T_MSG, 0, "DCC 적재 재검증 실패", 0L);
        userlog("[AC_DCC] 재검증 실패 code=%d", sqlca.sqlcode); FAIL(b);
    }
    if (h_txn_i != txn_int) {
        /* 반올림 경계 1 이내 허용, 그 외 불일치는 실패 처리 */
        long d = h_txn_i - txn_int; if (d < 0) d = -d;
        if (d > 1) {
            setl(b, T_RC, 8741); Bchg(b, T_MSG, 0, "DCC 환산 불일치(보상 롤백)", 0L);
            userlog("[AC_DCC] 환산 불일치 db=%ld calc=%ld", h_txn_i, txn_int); FAIL(b);
        }
        txn_int = h_txn_i;
    }

    /* ===== 7) 응답부 (계약: T_AMT1=txn_amount, T_STR2=txn_ccy, T_ARG1=fx_rate) ===== */
    setl(b, T_AMT1, txn_int);
    Bchg(b, T_STR2, 0, h_ccy, 0L);
    setl(b, T_ARG1, fx_int);
    setl(b, T_AMT2, h_base);
    setl(b, T_ID1, h_dcc);
    Bchg(b, T_STATUS, 0, h_status, 0L);
    Bchg(b, T_CCY, 0, h_ccy, 0L);
    Bchg(b, T_SVCNAME, 0, "AC_DCC", 0L);
    setl(b, T_RC, 0);

    /* ===== 8) 완료 로깅 ===== */
    userlog("[다통화] DCC 환산 완료 pid=%ld dcc=%ld base=%ld -> %ld %s", h_pid, h_dcc, h_base, txn_int, h_ccy);
    OK(b);
}

/* vim: set ts=4 sw=4 et smartindent: */
