/*
 * MM_BIN_REG.pgc - mm 모듈 서비스 MM_BIN_REG (one service = one file).
 * 기능: BIN 마스터 등록.
 * 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
 * mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
 */
#include "MM_BIN_REG.h"

void MM_BIN_REG(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    char bin[16], issuer[32], brand[16];
    EXEC SQL BEGIN DECLARE SECTION;
    char h_bin[16], h_issuer[32], h_brand[16];
    EXEC SQL END DECLARE SECTION;
    gets_(b, T_KEY1, bin, sizeof(bin));
    if (bin[0] == 0) { userlog("MM_BIN_REG: T_KEY1(bin) 누락"); FAIL(b); }
    gets_(b, T_ISSUER, issuer, sizeof(issuer)); if (issuer[0] == 0) strcpy(issuer, "UNKNOWN");
    gets_(b, T_STR5, brand, sizeof(brand));     if (brand[0] == 0) strcpy(brand, "LOCAL");
    strncpy(h_bin,    bin,    sizeof(h_bin)-1);    h_bin[sizeof(h_bin)-1]       = 0;
    strncpy(h_issuer, issuer, sizeof(h_issuer)-1); h_issuer[sizeof(h_issuer)-1] = 0;
    strncpy(h_brand,  brand,  sizeof(h_brand)-1);  h_brand[sizeof(h_brand)-1]   = 0;

    EXEC SQL INSERT INTO mm_bin (bin, issuer_cd, card_brand)
        VALUES (:h_bin, :h_issuer, :h_brand)
        ON CONFLICT (bin) DO UPDATE
        SET issuer_cd = EXCLUDED.issuer_cd, card_brand = EXCLUDED.card_brand;
    if (sqlca.sqlcode < 0) { userlog("MM_BIN_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }

    /* ====================================================================
     * [심화 후처리] MM_BIN_REG - 참조 마스터(BIN/발급사/환율) 정합/감사 확장부
     * 참조 마스터 규모와 발급사 연계 정합성을 재점검하고 감사 로그를 남긴다.
     * ==================================================================== */
    {
        EXEC SQL BEGIN DECLARE SECTION;
        char  zx_svc[24], zx_key[64], zx_msg[192];
        long  zx_logid, zx_n1, zx_n2, zx_n3, zx_bps, zx_bins, zx_iss;
        EXEC SQL END DECLARE SECTION;
        char  zx_in[64];
        long  zx_depth = 0, zx_score = 0, zx_fee = 0, zx_vat = 0, zx_wht = 0;

        /* (1) 입력 재확인부: 참조 키 확보 (T_KEY1/T_ISSUER/T_CCY) */
        strcpy(zx_svc, "MM_BIN_REG");
        gets_(b, T_KEY1, zx_in, sizeof(zx_in));
        if (zx_in[0] == 0) gets_(b, T_ISSUER, zx_in, sizeof(zx_in));
        if (zx_in[0] == 0) gets_(b, T_CCY, zx_in, sizeof(zx_in));
        if (zx_in[0] == 0) strcpy(zx_in, "-");
        strncpy(zx_key, zx_in, sizeof(zx_key)-1); zx_key[sizeof(zx_key)-1] = 0;
        zx_bps = 0;

        /* (2) 참조 마스터 규모 조회부: BIN/발급사 총수 */
        zx_bins = 0; zx_iss = 0;
        EXEC SQL SELECT count(*) INTO :zx_bins FROM mm_bin;
        if (sqlca.sqlcode < 0) FAIL(b);
        EXEC SQL SELECT count(*) INTO :zx_iss FROM mm_issuer WHERE status = 'ACTIVE';
        if (sqlca.sqlcode < 0) FAIL(b);
        zx_n1 = zx_bins; zx_n2 = zx_iss;

        /* (3) 업무규칙 분기부: 마스터 적재 규모별 운영 상태 판정 */
        if (zx_bins == 0 && zx_iss == 0) {
            zx_depth = 0; zx_score = 0;          /* 참조 마스터 공백 */
        } else if (zx_bins > 100) {
            zx_depth = 3; zx_score = 85;         /* 대규모 BIN 운영 */
        } else if (zx_iss > 0) {
            zx_depth = 2; zx_score = 60;         /* 발급사 연계 정상 */
        } else {
            zx_depth = 1; zx_score = 35;         /* 최소 구성 */
        }

        /* (6) 발급사-BIN 연계 정합 재집계부: 고아 BIN 탐지 */
        zx_n3 = 0;
        EXEC SQL SELECT count(*) INTO :zx_n3 FROM mm_bin bn
            WHERE bn.issuer_cd <> 'UNKNOWN'
              AND NOT EXISTS (SELECT 1 FROM mm_issuer iss
                              WHERE iss.issuer_cd = bn.issuer_cd);
        if (sqlca.sqlcode < 0) FAIL(b);

        /* (2b) 영업일/공휴일 정책 조회 (정산 스케줄 판정 보조) */
        {
            char zc_today[16], zc_next[16];
            int  zc_hol;
            EXEC SQL BEGIN DECLARE SECTION;
            char zc_hd[16];
            long zc_holcnt;
            EXEC SQL END DECLARE SECTION;
            EXEC SQL SELECT to_char(current_date, 'YYYY-MM-DD') INTO :zc_hd;
            if (sqlca.sqlcode < 0) FAIL(b);
            strncpy(zc_today, zc_hd, sizeof(zc_today)-1); zc_today[sizeof(zc_today)-1] = 0;
            acq_next_bizday(zc_today, zc_next);
            zc_hol = mmdb_is_holiday(zc_today);
            EXEC SQL SELECT count(*) INTO :zc_holcnt FROM mm_holiday;
            if (sqlca.sqlcode < 0) FAIL(b);
            if (zc_hol > 0)          userlog("MM_BIN_REG 금일 공휴일 -> 익영업일 %s", zc_next);
            else if (zc_holcnt == 0) userlog("MM_BIN_REG 공휴일 마스터 미적재 (기본 스케줄)");
            else                     userlog("MM_BIN_REG 영업일 처리 익영업일=%s 공휴일수=%ld", zc_next, zc_holcnt);
        }

        /* (4) 본처리 계산부: 기준금액 수수료/부가세/원천 산출 (공통유틸) */
        zx_fee = acq_fee(1000000, zx_bps > 0 ? zx_bps : 25);
        zx_vat = acq_vat(zx_fee);
        zx_wht = acq_wht_amt(zx_fee, 330);
        if (zx_score < 0) zx_score = 0;
        if (zx_score > 100) zx_score = 100;

        /* (7) 감사 로그 적재부: cm_log 처리요약 1건 (실패 시 XA 롤백) */
        EXEC SQL SELECT nextval('cm_log_seq') INTO :zx_logid;
        if (sqlca.sqlcode < 0) FAIL(b);
        snprintf(zx_msg, sizeof(zx_msg),
            "MM_BIN_REG key=%s d=%ld n1=%ld n2=%ld score=%ld fee=%ld",
            zx_key, zx_depth, zx_n1, zx_n2, zx_score, zx_fee);
        EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
            VALUES (:zx_logid, :zx_svc, 'I', :zx_msg, current_date);
        if (sqlca.sqlcode < 0) FAIL(b);

        /* (9) 완료 로깅부: 진입 키/분기/집계 결과 감사 추적 */
        userlog("MM_BIN_REG 확장후처리 key=%s 분기심도=%ld 점수=%ld", zx_key, zx_depth, zx_score);
        userlog("MM_BIN_REG 집계 n1=%ld n2=%ld n3=%ld", zx_n1, zx_n2, zx_n3);
        userlog("MM_BIN_REG 수수료 fee=%ld vat=%ld wht=%ld bps=%ld", zx_fee, zx_vat, zx_wht, zx_bps);
        (void)zx_vat; (void)zx_wht; (void)zx_n3;
    }


    /* ---- 업무 체인: MM_BIN_REG -> VL_BIN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ----
     * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다.
     * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는
     * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다.
     * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을
     * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */
    {
        long ch_rlen = 0;
        int  ch_do = 1;
        char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant));
        if (ch_do) {
            { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc));
              if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } }
            if (tpcall("VL_BIN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) {
                userlog("[MM_BIN_REG] tpcall(VL_BIN) 실패: %s", tpstrerror(tperrno));
                setl(b, T_RC, 7141);
                Bchg(b, T_MSG, 0, "BIN 정합검증 체인 실패", 0L);
                FAIL(b);
            }
            /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */
            userlog("[MM_BIN_REG] 정합검증 연동 완료 rc=%ld", getl(b, T_RC));
            Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L);
        } else {
            userlog("[MM_BIN_REG] 체인 대상 컨텍스트 없음 - VL_BIN 호출 생략");
        }
    }

    OK(b);
}
