/*
 * CM_SEQ.pgc - cm 모듈 서비스 CM_SEQ (one service = one file).
 * Split out of the former inline cm_svr.pgc; runs on the caller's XA
 * branch (no EXEC SQL CONNECT). Advertised by cm_svr at tpsvrinit.
 */
#include "CM_SEQ.h"

/* 10. CM_SEQ - 공통 채번 (cm_seq 이름있는 카운터). */

/* ------------------------------------------------------------------ */
/* 원 서비스 핵심 로직 - 입출력 필드 계약 보존 (0=정상, -1=실패).        */
/* ------------------------------------------------------------------ */
static int CM_SEQ__core(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    char name[32];
    long v;
    gets_(b, T_KEY1, name, sizeof(name)); if (name[0] == 0) strcpy(name, "BATCH");
    v = cmdb_next_seq(name);
    if (v < 0) return -1;
    setl(b, T_ARG1, v);
    return 0;
    return 0;
}

/* CM_SEQ 심화용 보조 판정 - 처리등급 산정. */
static int CM_SEQ__grade(long v)
{
    if (v <= 0)          return 0;   /* 대상없음 */
    if (v < 42L)         return 1;   /* 소량 */
    if (v < 1472L)         return 2;   /* 보통 */
    if (v < 100472L)         return 3;   /* 대량 */
    return 4;                        /* 초대량 */
}

/* CM_SEQ - 공통 채번 (cm_seq 이름있는 카운터).. 심화: 검증/정책조회/업무분기/감사/집계 보강. */
void CM_SEQ(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    EXEC SQL BEGIN DECLARE SECTION;
    char hz_bizdate[16];
    char hz_key[64];
    char hz_pval[128];
    char hz_txt[128];
    long hz_cnt;
    long hz_sum;
    long hz_v1;
    long hz_v2;
    EXEC SQL END DECLARE SECTION;
    long rc = 0, core_rc = 0, aud_id = 0, band = 0, grade = 0;
    long in_amt = 0, in_arg = 0, agg = 0, policy = 0;
    char ins[64], msg[200];
    int vlen = 0, vi = 0;

    userlog("CM_SEQ 진입: 공통 채번 (cm_seq 이름있는 카운터). (svc=CM_SEQ)");

    /* 1) 입력 검증부 - 필수/범위/형식 확인. */
    if (cmdb_get_param("BIZ_DATE", hz_bizdate) < 0)
        strcpy(hz_bizdate, "2026-07-19");
    gets_(b, T_BIZDATE, ins, sizeof(ins));
    if (ins[0] != 0) {
        int yy = 0, mm = 0, dd = 0;
        if (sscanf(ins, "%d-%d-%d", &yy, &mm, &dd) != 3) {
            setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "영업일 형식 오류(YYYY-MM-DD)", 0L); FAIL(b);
        }
        if (mm < 1 || mm > 12 || dd < 1 || dd > 31) {
            setl(b, T_RC, 92); Bchg(b, T_MSG, 0, "영업일 월/일 범위 오류", 0L); FAIL(b);
        }
        strncpy(hz_bizdate, ins, sizeof(hz_bizdate)-1);
        hz_bizdate[sizeof(hz_bizdate)-1] = 0;
    }
    in_amt = getl(b, T_AMOUNT);
    in_arg = getl(b, T_ARG1);
    if (in_amt < 0) {
        setl(b, T_RC, 93); Bchg(b, T_MSG, 0, "금액이 음수입니다", 0L); FAIL(b);
    }
    gets_(b, T_STR1, ins, sizeof(ins));
    for (vi = 0; ins[vi]; vi++) vlen++;
    if (vlen > 60) {
        setl(b, T_RC, 94); Bchg(b, T_MSG, 0, "입력 문자열이 너무 깁니다", 0L); FAIL(b);
    }

    /* 2) 정책/마스터 조회부 - 관련 기준정보 로드 후 분기. */
    gets_(b, T_KEY1, hz_key, sizeof(hz_key)); if (hz_key[0] == 0) strcpy(hz_key, "BATCH");
    EXEC SQL SELECT coalesce(seq_val,0) INTO :hz_v1 FROM cm_seq WHERE seq_name = :hz_key;
    if (sqlca.sqlcode == 100) { userlog("CM_SEQ 신규 시퀀스 key=%s", hz_key); hz_v1 = 0; }
    else if (sqlca.sqlcode < 0) { userlog("CM_SEQ 시퀀스 조회 오류"); }
    policy = hz_v1;   /* 현재 시퀀스 값 */

    /* 3) 업무규칙 분기부 - 상태/구간/등급별 경로 분리. */
    band = in_amt + in_arg;
    if (policy < 0) {
        grade = 0; userlog("CM_SEQ 기준정보 이상 - 보류");
    } else if (policy == 0) {
        grade = 1;   /* 최초 처리 */
    } else if (policy < 172L) {
        grade = 2;   /* 통상 처리 */
    } else {
        grade = 3; userlog("CM_SEQ 누적 과다 policy=%ld", policy);
    }
    if (grade >= 3 && band > 104720L) {
        userlog("CM_SEQ 임계 초과 - 감사강화 band=%ld", band);
    }

    /* 4) 본처리부 - 원 서비스 핵심 로직 수행(계산/DB 반영). */
    core_rc = CM_SEQ__core(p);
    if (core_rc != 0) {
        setl(b, T_RC, 20);
        Bchg(b, T_MSG, 0, "핵심 처리 실패 - 롤백", 0L);
        userlog("CM_SEQ 실패: core_rc=%ld", core_rc);
        FAIL(b);
    }

    /* 5) 이력/감사 적재부 - cm_log 에 처리 요약 기록. */
    grade = CM_SEQ__grade(in_amt + in_arg + agg);
    snprintf(msg, sizeof(msg), "CM_SEQ 처리 grade=%ld policy=%ld agg=%ld",
             grade, policy, agg);
    aud_id = cmdb_log("CM_SEQ", grade >= 3 ? "W" : "I", msg, hz_bizdate);
    if (aud_id < 0) {
        Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L);
        setl(b, T_RC, 30);
        FAIL(b);
    }

    /* 6) 집계/요약 갱신부 - 처리 결과 재집계(SELECT 기반). */
    EXEC SQL SELECT coalesce(sum(seq_val),0) INTO :hz_v1 FROM cm_seq;
    agg = (sqlca.sqlcode == 0) ? hz_v1 : 0;   /* 전체 시퀀스 총합 */
    if (agg > 1472L)
        userlog("CM_SEQ 집계 임계 agg=%ld", agg);

    /* 7) 예외/보상부 - 집계 재조회 실패시 전체 롤백. */
    if (sqlca.sqlcode < 0) {
        userlog("CM_SEQ 집계 조회 오류 sqlcode=%d", sqlca.sqlcode);
        Bchg(b, T_MSG, 0, "집계 재조회 오류", 0L);
        setl(b, T_RC, 40);
        FAIL(b);
    }

    /* 8) 응답부 - 결과 필드 채움. */
    setl(b, T_ARG8, aud_id);
    setl(b, T_ARG7, agg);
    setl(b, T_ARG6, grade);
    setl(b, T_RC, 0);

    userlog("CM_SEQ 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg);

    /* ---- 업무 체인: CM_SEQ -> CM_LOG (동일 글로벌 트랜잭션 / 별도 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_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_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_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname));
        if (ch_do) {
            Bchg(b, T_SVCNAME, 0, "CM_SEQ", 0L);
            Bchg(b, T_MSG, 0, "공통 채번 수행", 0L);
            Bchg(b, T_STR1, 0, "CM_SEQ", 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_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) {
                userlog("[CM_SEQ] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno));
                setl(b, T_RC, 7301);
                Bchg(b, T_MSG, 0, "채번 이력 적재 체인 실패", 0L);
                FAIL(b);
            }
            /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */
            userlog("[CM_SEQ] 이력 연동 완료 log_id=%ld", getl(b, T_ID1));
            setl(b, T_AMOUNT, ch_o_amount);
            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_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_SVCNAME, 0, ch_o_svcname, 0L);
        } else {
            userlog("[CM_SEQ] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략");
        }
    }

    OK(b);
}
