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

/* MG_REVRSP - 0410 취소응답 생성: 원 0400 취소요청(STAN)을 조회해 취소응답전문
 *   0410 을 OUT 으로 채번·적재하고, 원 취소요청을 취소완료(rc=00/status=C)로 전이. */
void MG_REVRSP(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;

    /* ===================================================================
     * 심화 처리부 (전문 파싱/비트맵/체크섬/MAC - 순수계산) - MG_REVRSP
     * 필드형식검증 / 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 = 85L;

        /* --- 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_REVRSP 심화계산 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 chan[16], bizdate[16], rc[4];
    long orig_stan, orig_id, stan, msg_id, amount;

    gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    amount = getl(b, T_AMOUNT);
    orig_stan = getl(b, T_ARG1);
    if (orig_stan <= 0) { setl(b, T_RC, 13); FAIL(b); }

    orig_id = mgdb_find_msg_by_stan(orig_stan);
    strcpy(rc, (orig_id < 0) ? "25" : "00");   /* 25 = 원거래 없음 */

    stan = mgdb_next_stan();     if (stan < 0) FAIL(b);
    msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
    if (mgdb_insert_msg(msg_id, stan, "0410", chan, "OUT", "000000", "", amount,
                        "", rc, "", "S", bizdate) < 0) FAIL(b);
    if (orig_id >= 0 && mgdb_update_msg_rc(orig_id, "00", "C") < 0) FAIL(b);

    sets_(b, T_STR2, rc);
    setl(b, T_ID1, msg_id);
    setl(b, T_RC, (orig_id < 0) ? 25 : 0);
    OK(b);
}
