/*
 * MM_BIZNO_CHECK.pgc - mm 모듈 서비스 MM_BIZNO_CHECK (one service = one file).
 * 기능: 사업자등록번호 검증 (10자리 형식 + 국세청 검증공식 checksum + 마스터 중복 사용 확인).
 * checksum: 가중치 1,3,7,1,3,7,1,3,5 곱 합 + floor(9번째*5/10), (10-합%10)%10 == 검증숫자.
 * 입력: T_STR2=사업자번호. 출력: T_COUNT=해당 번호를 쓰는 기존 가맹점 수.
 * RC: 0=유효, 2=형식 오류, 3=검증숫자 불일치.
 * caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
 */
#include "MM_BIZNO_CHECK.h"

static int bizno_checksum_ok(const char *no)
{
    static const int w[9] = { 1, 3, 7, 1, 3, 7, 1, 3, 5 };
    int i, sum = 0;
    for (i = 0; i < 9; i++) sum += (no[i] - '0') * w[i];
    sum += ((no[8] - '0') * 5) / 10;
    return ((10 - sum % 10) % 10) == (no[9] - '0');
}

void MM_BIZNO_CHECK(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    char bizno[16];
    int i;
    EXEC SQL BEGIN DECLARE SECTION;
    char h_bizno[16];
    long h_used;
    EXEC SQL END DECLARE SECTION;

    gets_(b, T_STR2, bizno, sizeof(bizno));
    if (strlen(bizno) != 10) { setl(b, T_RC, 2); OK(b); }
    for (i = 0; i < 10; i++)
        if (bizno[i] < '0' || bizno[i] > '9') { setl(b, T_RC, 2); OK(b); }
    if (!bizno_checksum_ok(bizno)) { setl(b, T_RC, 3); OK(b); }

    strncpy(h_bizno, bizno, sizeof(h_bizno)-1); h_bizno[sizeof(h_bizno)-1] = 0;
    EXEC SQL SELECT count(*) INTO :h_used FROM mm_merchant_ext
        WHERE biz_reg_no = :h_bizno AND status <> 'DELETED';
    if (sqlca.sqlcode < 0) FAIL(b);

    setl(b, T_COUNT, h_used);
    setl(b, T_RC, 0);

    /* ====================================================================
     * [심화 후처리] MM_BIZNO_CHECK - 가맹점 마스터 정합/감사/집계 확장부 (mm 공통)
     * 원 서비스의 입출력 계약은 위에서 확정되며, 이하는 부가 감사/집계만 수행한다.
     * ==================================================================== */
    {
        EXEC SQL BEGIN DECLARE SECTION;
        char  zx_svc[24], zx_key[64], zx_grade[8], zx_stat[16], zx_msg[192];
        long  zx_logid, zx_n1, zx_n2, zx_n3, zx_bps, zx_lim, zx_gross;
        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) 입력 재확인부: 가맹점 키 확보 (미보유 서비스는 '-' 대체) */
        strcpy(zx_svc, "MM_BIZNO_CHECK");
        gets_(b, T_MERCHANT, zx_in, sizeof(zx_in));
        if (zx_in[0] == 0) gets_(b, T_KEY1, 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;

        /* (2) 마스터/정책 조회부: 현행 등급·상태 + 요율/한도 로드 */
        strcpy(zx_grade, "C"); strcpy(zx_stat, "NONE");
        EXEC SQL SELECT coalesce(grade,'C'), coalesce(status,'NONE')
            INTO :zx_grade, :zx_stat
            FROM mm_merchant_ext WHERE merchant_id = :zx_key;
        if (sqlca.sqlcode < 0) FAIL(b);
        if (sqlca.sqlcode == 100) { strcpy(zx_grade, "C"); strcpy(zx_stat, "NONE"); }
        zx_bps = 0;
        EXEC SQL SELECT coalesce(min(rate_bps),0) INTO :zx_bps
            FROM mm_fee_rate WHERE merchant_id = :zx_key;
        if (sqlca.sqlcode < 0) FAIL(b);
        zx_lim = 0;
        EXEC SQL SELECT coalesce(max(daily_limit),0) INTO :zx_lim
            FROM mm_limit WHERE merchant_id = :zx_key;
        if (sqlca.sqlcode < 0) FAIL(b);

        /* (3) 업무규칙 분기부: 등급/상태/요율에 따른 감사 심도·점수 산정 */
        if (strcmp(zx_stat, "ACTIVE") == 0 && zx_grade[0] == 'S') {
            zx_depth = 3; zx_score = 90;
        } else if (zx_grade[0] == 'A' || zx_grade[0] == 'B') {
            zx_depth = 2; zx_score = 70;
        } else if (strcmp(zx_stat, "NONE") == 0) {
            zx_depth = 0; zx_score = 0;
        } else {
            zx_depth = 1; zx_score = 45;
        }
        if (zx_bps == 0)   zx_score -= 10;
        if (zx_lim > 0 && zx_lim < 1000000) zx_score -= 5;

        /* (5) 이력/집계 조회부: 변경 이력 건수 + 활성 마스터 총수 */
        zx_n1 = 0;
        EXEC SQL SELECT count(*) INTO :zx_n1
            FROM mm_merch_hist WHERE merchant_id = :zx_key;
        if (sqlca.sqlcode < 0) FAIL(b);
        zx_n2 = 0;
        EXEC SQL SELECT count(*) INTO :zx_n2
            FROM mm_merchant_ext WHERE status = 'ACTIVE';
        if (sqlca.sqlcode < 0) FAIL(b);

        /* (6) 요약 재집계부: 최근 매출 + 등급통계 최신 카운트 */
        zx_gross = 0;
        EXEC SQL SELECT coalesce(sum(gross_amount),0) INTO :zx_gross
            FROM merchant_summary WHERE merchant_id = :zx_key;
        if (sqlca.sqlcode < 0) FAIL(b);
        zx_n3 = zx_gross;
        EXEC SQL SELECT coalesce(sum(merch_cnt),0) INTO :zx_n3
            FROM mm_grade_stat
            WHERE stat_date = (SELECT max(stat_date) FROM mm_grade_stat);
        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_BIZNO_CHECK 금일 공휴일 -> 익영업일 %s", zc_next);
            else if (zc_holcnt == 0) userlog("MM_BIZNO_CHECK 공휴일 마스터 미적재 (기본 스케줄)");
            else                     userlog("MM_BIZNO_CHECK 영업일 처리 익영업일=%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_BIZNO_CHECK 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_BIZNO_CHECK 확장후처리 key=%s 분기심도=%ld 점수=%ld", zx_key, zx_depth, zx_score);
        userlog("MM_BIZNO_CHECK 집계 n1=%ld n2=%ld n3=%ld", zx_n1, zx_n2, zx_n3);
        userlog("MM_BIZNO_CHECK 수수료 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_BIZNO_CHECK -> CM_CHECKDIGIT (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ----
     * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다.
     * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는
     * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다.
     * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을
     * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */
    {
        long ch_rlen = 0;
        int  ch_do = 1;
        long ch_o_amount = getl(b, T_AMOUNT);
        char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate));
        long ch_o_count = getl(b, T_COUNT);
        long ch_o_rc = getl(b, T_RC);
        char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2));
        if (ch_do) {
            { char ch_bs[32]; gets_(b, T_STR2, ch_bs, sizeof(ch_bs));
              if (ch_bs[0] == 0) strcpy(ch_bs, "0000000000");
              Bchg(b, T_STR2, 0, ch_bs, 0L); }
            if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0);
            { 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 (tpcall("CM_CHECKDIGIT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) {
                userlog("[MM_BIZNO_CHECK] tpcall(CM_CHECKDIGIT) 실패: %s", tpstrerror(tperrno));
                setl(b, T_RC, 7163);
                Bchg(b, T_MSG, 0, "사업자번호 검증 체인 실패", 0L);
                FAIL(b);
            }
            /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */
            userlog("[MM_BIZNO_CHECK] 검증번호 연동 d=%ld", getl(b, T_ARG1));
            setl(b, T_AMOUNT, ch_o_amount);
            Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L);
            setl(b, T_COUNT, ch_o_count);
            setl(b, T_RC, ch_o_rc);
            Bchg(b, T_STR2, 0, ch_o_str2, 0L);
        } else {
            userlog("[MM_BIZNO_CHECK] 체인 대상 컨텍스트 없음 - CM_CHECKDIGIT 호출 생략");
        }
    }

    OK(b);
}
