/*
 * MG_DECODE.pgc - mg 모듈 서비스 MG_DECODE (one service = one file).
 * 신규 스케일아웃 서비스; 캘러의 XA 브랜치에서 실행. mg_svr 가 광고.
 */
#include "MG_DECODE.h"

/* MG_DECODE - 확장 고정길이 해체(순수계산): MG_ENCODE 가 만든 32자 프레임을
 *   MTI/처리코드/금액/STAN/채널 필드로 되돌린다. 길이 32 미만이면 rc=31. */
void MG_DECODE(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;

    /* ===================================================================
     * 심화 처리부 (전문 파싱/비트맵/체크섬/MAC - 순수계산) - MG_DECODE
     * 필드형식검증 / 1·2차 비트맵 구성 / LRC·합계 체크섬 / 간이 MAC /
     * PAN Luhn / 금액밴드 / 필드추출 / 응답보조 / 로깅
     * =================================================================== */
    {
        char gw_mti[8], gw_proc[8], gw_raw[512], gw_pan[24];
        char gw_bmp1[24], gw_bmp2[24], gw_fld[64];
        unsigned long gw_mask1, gw_mask2, gw_mac;
        long gw_amount, gw_len, gw_i, gw_lrc, gw_sum, gw_present;
        long gw_band, gw_valid, gw_luhn, gw_digsum, gw_thr;

        /* --- 1) 입력 캡처 --------------------------------------------- */
        gets_(b, T_STR1, gw_mti, sizeof(gw_mti));   if (gw_mti[0] == 0)  strcpy(gw_mti, "0200");
        gets_(b, T_STR4, gw_proc, sizeof(gw_proc)); if (gw_proc[0] == 0) strcpy(gw_proc, "000000");
        gets_(b, T_STR3, gw_raw, sizeof(gw_raw));
        gets_(b, T_STR5, gw_pan, sizeof(gw_pan));
        gw_amount = getl(b, T_AMOUNT);
        gw_len = (long)strlen(gw_raw);
        gw_thr = 83L;

        /* --- 2) 필드 형식 검증: MTI/처리코드 숫자성 -------------------- */
        gw_valid = 1;
        for (gw_i = 0; gw_i < 4 && gw_mti[gw_i]; gw_i++)
            if (gw_mti[gw_i] < '0' || gw_mti[gw_i] > '9') gw_valid = 0;
        if (!gw_valid) { setl(b, T_RC, 9401); sets_(b, T_MSG, "MTI 비숫자 포함"); FAIL(b); }
        for (gw_i = 0; gw_i < 6 && gw_proc[gw_i]; gw_i++)
            if (gw_proc[gw_i] < '0' || gw_proc[gw_i] > '9') gw_valid = 0;
        if (!gw_valid) { setl(b, T_RC, 9402); sets_(b, T_MSG, "처리코드 비숫자 포함"); FAIL(b); }

        /* --- 3) 1차 비트맵 구성 (존재필드 마스크) --------------------- */
        gw_mask1 = 0;
        gw_mask1 |= (1UL << 63);                 /* F1: 2차 비트맵 지시 */
        if (gw_pan[0])   gw_mask1 |= (1UL << 62); /* F2: PAN */
        if (gw_proc[0])  gw_mask1 |= (1UL << 61); /* F3: 처리코드 */
        if (gw_amount)   gw_mask1 |= (1UL << 60); /* F4: 금액 */
        if (gw_len > 0)  gw_mask1 |= (1UL << 52); /* F11: STAN 존재 */
        sprintf(gw_bmp1, "%016lX", gw_mask1);

        /* --- 4) 2차 비트맵 구성 (확장필드) --------------------------- */
        gw_mask2 = 0;
        if (gw_amount >= 1000000L) gw_mask2 |= (1UL << 63); /* F65: 고액표식 */
        if (gw_len >= 38)          gw_mask2 |= (1UL << 60); /* F68: 확장데이터 */
        sprintf(gw_bmp2, "%016lX", gw_mask2);

        /* --- 5) 존재필드 수 계산 ------------------------------------- */
        gw_present = 0;
        for (gw_i = 0; gw_i < 64; gw_i++)
            if (gw_mask1 & (1UL << gw_i)) gw_present++;

        /* --- 6) LRC/합계 체크섬 (raw XOR + 누적합) ------------------- */
        gw_lrc = 0; gw_sum = 0;
        for (gw_i = 0; gw_i < gw_len; gw_i++) {
            gw_lrc ^= (unsigned char)gw_raw[gw_i];
            gw_sum += (unsigned char)gw_raw[gw_i];
        }

        /* --- 7) 간이 MAC (회전 누산 해시) --------------------------- */
        gw_mac = 0;
        for (gw_i = 0; gw_i < gw_len; gw_i++)
            gw_mac = ((gw_mac << 5) ^ (gw_mac >> 2)
                      ^ (unsigned long)(unsigned char)gw_raw[gw_i]) & 0xFFFFFFUL;

        /* --- 8) PAN Luhn / 금액밴드 / 금액자리합 -------------------- */
        gw_luhn = (gw_pan[0] && acq_luhn_ok(gw_pan)) ? 1 : 0;
        gw_band = (gw_amount >= 1000000L) ? 3 : (gw_amount >= 100000L) ? 2
                : (gw_amount > 0) ? 1 : 0;
        { long gw_a = gw_amount; gw_digsum = 0;
           if (gw_a < 0) gw_a = -gw_a;
           while (gw_a > 0) { gw_digsum += gw_a % 10; gw_a /= 10; } }
        if (gw_band == 3 && gw_present < 3) {
            setl(b, T_RC, 9403); sets_(b, T_MSG, "고액전문 필수필드 누락"); FAIL(b);
        }

        /* --- 9) 필드추출 데모 + 응답보조(심화전용 필드) + 로깅 ------ */
        /* (원 서비스가 입력으로 읽지 않는 필드만 사용해 I/O 계약 보존) */
        memset(gw_fld, 0, sizeof(gw_fld));
        if (gw_len >= 10) strncpy(gw_fld, gw_raw + 4, 6);
        setl(b, T_ARG6, gw_present);
        setl(b, T_ARG7, gw_band);
        setl(b, T_ARG8, gw_digsum);
        setl(b, T_AMT2, gw_sum);
        setl(b, T_AMT3, gw_lrc);
        sets_(b, T_STR8, gw_bmp1);
        (void)gw_bmp2; (void)gw_luhn; (void)gw_mac; (void)gw_fld;
        userlog("MG_DECODE 심화계산 mti=%s bmp1=%s present=%ld lrc=%ld mac=%06lX band=%ld thr=%ld",
                gw_mti, gw_bmp1, gw_present, gw_lrc, gw_mac, gw_band, gw_thr);
    }
    char raw[64], mti[8], proc[8], chan[8];
    long amount, stan, n;

    gets_(b, T_STR3, raw, sizeof(raw));
    n = (long)strlen(raw);
    if (n < 32) { setl(b, T_RC, 31); FAIL(b); }

    memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc)); memset(chan, 0, sizeof(chan));
    strncpy(mti, raw, 4);
    strncpy(proc, raw + 4, 6);
    amount = atol(raw + 10);            /* [10..21] 금액 12 */
    stan = atol(raw + 22);             /* [22..27] STAN 6 */
    strncpy(chan, raw + 28, 4);        /* [28..31] 채널 4 */

    sets_(b, T_STR1, mti);
    sets_(b, T_STR4, proc);
    setl(b, T_AMOUNT, amount);
    setl(b, T_ARG1, stan);
    sets_(b, T_CHANNEL, chan);
    setl(b, T_RC, 0);

    /* ---- 업무 체인: MG_DECODE -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ----
     * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다.
     * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는
     * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다.
     * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을
     * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */
    {
        long ch_rlen = 0;
        int  ch_do = 1;
        long ch_o_amount = getl(b, T_AMOUNT);
        long ch_o_amt2 = getl(b, T_AMT2);
        long ch_o_amt3 = getl(b, T_AMT3);
        long ch_o_arg1 = getl(b, T_ARG1);
        long ch_o_arg6 = getl(b, T_ARG6);
        long ch_o_arg7 = getl(b, T_ARG7);
        long ch_o_arg8 = getl(b, T_ARG8);
        char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate));
        char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel));
        char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg));
        long ch_o_rc = getl(b, T_RC);
        char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1));
        char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4));
        char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8));
        if (ch_do) {
            { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch));
              if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); }
            sets_(b, T_STR1, "0200");
            { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd));
              if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); }
            if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0);
            if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) {
                userlog("[MG_DECODE] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno));
                setl(b, T_RC, 7217);
                Bchg(b, T_MSG, 0, "전문 디코딩 파싱 체인 실패", 0L);
                FAIL(b);
            }
            /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */
            userlog("[MG_DECODE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC));
            setl(b, T_AMOUNT, ch_o_amount);
            setl(b, T_AMT2, ch_o_amt2);
            setl(b, T_AMT3, ch_o_amt3);
            setl(b, T_ARG1, ch_o_arg1);
            setl(b, T_ARG6, ch_o_arg6);
            setl(b, T_ARG7, ch_o_arg7);
            setl(b, T_ARG8, ch_o_arg8);
            Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L);
            Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L);
            Bchg(b, T_MSG, 0, ch_o_msg, 0L);
            setl(b, T_RC, ch_o_rc);
            Bchg(b, T_STR1, 0, ch_o_str1, 0L);
            Bchg(b, T_STR4, 0, ch_o_str4, 0L);
            Bchg(b, T_STR8, 0, ch_o_str8, 0L);
        } else {
            userlog("[MG_DECODE] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략");
        }
    }

    OK(b);
}
