/*
 * RC_DEPGAP.pgc - rc 모듈 서비스 RC_DEPGAP (대사 온라인 프로그램, 심화판).
 * 업무: 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계.
 * 처리단계: 입력검증->마스터/정책조회->업무규칙분기->본처리->이력적재->집계갱신->예외보상->응답.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). rc_svr 가 tpsvrinit 에서 광고.
 */
#include "RC_DEPGAP.h"
#include "acq_common.h"

/* RC_DEPGAP - 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계. */
void RC_DEPGAP(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    char  bizdate[16], tmpin[64];
    char  sbuf[300];
    long  tol = 0, rc_code = 0, adiff = 0, out_cnt = 0, pctl = 0;
    long  scan_rows = 0, matched_rows = 0, unmatched_rows = 0, unmatched_amt = 0;
    EXEC SQL BEGIN DECLARE SECTION;
    long  h_pid, h_amt, h_fee, h_net, h_act, h_exp, h_gross, h_cnt;
    long  h_mcnt, h_ecnt, h_ucnt, h_led, h_set, h_id, h_id2, h_mdr;
    long  h_limit, h_sum, h_val, h_n1, h_n2, h_prev, h_diff;
    char  h_bizdate[16], h_nbizdate[16], h_merch[64], h_status[16], h_pstat[16];
    char  h_channel[16], h_issuer[40], h_category[16], h_ccy[8], h_reason[160];
    char  h_msg[256], h_svc[40], h_lvl[16], h_key[64], h_dtype[8];
    EXEC SQL END DECLARE SECTION;

    /* 지역/호스트 변수 초기화 (DECLARE SECTION 밖) */
    h_pid = h_amt = h_fee = h_net = h_act = h_exp = h_gross = h_cnt = 0;
    h_mcnt = h_ecnt = h_ucnt = h_led = h_set = h_id = h_id2 = h_mdr = 0;
    h_limit = h_sum = h_val = h_n1 = h_n2 = h_prev = h_diff = 0;
    bizdate[0] = tmpin[0] = 0;
    h_bizdate[0] = h_nbizdate[0] = h_merch[0] = 0;
    strcpy(h_status, "MATCHED"); strcpy(h_pstat, "A"); strcpy(h_ccy, "KRW");
    strcpy(h_channel, "POS"); strcpy(h_issuer, "UNKNOWN"); strcpy(h_category, "GEN");
    strcpy(h_reason, "DEPGAP_CHK"); strcpy(h_lvl, "I"); strcpy(h_dtype, "AMT");
    strcpy(h_svc, "RC_DEPGAP");
    snprintf(h_msg, sizeof(h_msg), "[RC_DEPGAP] 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계.");
    strcpy(h_key, "-");
    userlog("[RC_DEPGAP] 대사 진입: 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계.");

    /* [1] 입력 검증부 -------------------------------------------------- */
    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    if (strlen(bizdate) < 8) {
        setl(b, T_RC, 8001); Bchg(b, T_MSG, 0, "영업일자(biz_date) 형식 오류", 0L);
        userlog("[RC_DEPGAP] 영업일자 검증 실패 val=[%s]", bizdate); FAIL(b);
    }
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    strcpy(h_key, bizdate);

    /* [2] 마스터/정책/상태 조회부 ------------------------------------- */
    EXEC SQL SELECT count(*), coalesce(sum(amount),0), coalesce(sum(net),0), coalesce(sum(fee),0)
        INTO :h_cnt, :h_gross, :h_sum, :h_fee FROM purchase WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 당일 매입 집계 오류"); FAIL(b); }
    EXEC SQL SELECT count(*) INTO :h_mcnt FROM rc_match_log
        WHERE biz_date = :h_bizdate AND status = 'MATCHED';
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 대사 로그 집계 오류"); FAIL(b); }
    EXEC SQL SELECT count(*) INTO :h_ecnt FROM rc_exception
        WHERE biz_date = :h_bizdate AND resolved = false;
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 예외 집계 오류"); FAIL(b); }

    /* [3] 거래집합 커서 순회 + 허용오차/매칭분류 --------------------- */
    EXEC SQL DECLARE cur_rc_depgap CURSOR FOR
        SELECT purchase_id, net, amount, fee, status
          FROM purchase WHERE biz_date = :h_bizdate ORDER BY purchase_id;
    EXEC SQL OPEN cur_rc_depgap;
    for (;;) {
        EXEC SQL FETCH cur_rc_depgap INTO :h_pid, :h_net, :h_amt, :h_fee, :h_pstat;
        if (sqlca.sqlcode == 100) break;
        if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_rc_depgap; userlog("[RC_DEPGAP] 커서 FETCH 오류"); FAIL(b); }
        EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_act FROM ledger
            WHERE purchase_id = :h_pid AND entry_type IN ('RECON','SETTLE');
        if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_rc_depgap; FAIL(b); }
        h_exp = h_net; adiff = (h_exp - h_act); if (adiff < 0) adiff = -adiff;
        scan_rows++;
        if (adiff <= (tol > 0 ? tol : 0)) matched_rows++;
        else { unmatched_rows++; unmatched_amt += adiff; }
    }
    EXEC SQL CLOSE cur_rc_depgap;
    userlog("[RC_DEPGAP] 대사스캔 완료 scan=%ld match=%ld unmatch=%ld", scan_rows, matched_rows, unmatched_rows);

    /* [4] 업무규칙 분기부 (상태/금액/한도) ----------------------------- */
    if (h_gross <= 0 && scan_rows == 0) {
        rc_code = 0; strcpy(h_status, "NODATA"); out_cnt = 0;
        userlog("[RC_DEPGAP] 대상 없음 - 무처리 종료");
    } else if (unmatched_rows == 0) {
        rc_code = 0; strcpy(h_status, "MATCHED"); out_cnt = matched_rows;
    } else if (unmatched_rows * 100 <= (scan_rows > 0 ? scan_rows : 1) * 5) {
        rc_code = 1; strcpy(h_status, "TOLERATED"); out_cnt = unmatched_rows;
        userlog("[RC_DEPGAP] 경미 불일치 허용범위 내 unmatch=%ld", unmatched_rows);
    } else {
        rc_code = 2; strcpy(h_status, "EXCEPTION"); out_cnt = unmatched_rows;
        userlog("[RC_DEPGAP] 대사 불일치 초과 unmatch=%ld amt=%ld", unmatched_rows, unmatched_amt);
    }
    if (h_mdr > 0 && h_gross > 0) pctl = acq_fee(h_gross, h_mdr);   /* 이론 수수료 */
    h_exp = h_net; h_diff = h_exp - h_act;

    /* [5] 본처리부 (핵심 적재/갱신) ----------------------------------- */
    /* 예외 적재 (rc_exception) */
    if (h_ecnt >= 0) {
        h_id = rcdb_insert_exception(h_pid, h_reason, bizdate);
        if (h_id < 0) { userlog("[RC_DEPGAP] 예외 적재 실패 pid=%ld", h_pid); FAIL(b); }
    }
    out_cnt = h_ecnt + (h_pid > 0 ? 1 : 0);

    /* [6] 이력/감사 적재부 (cm_log) ----------------------------------- */
    EXEC SQL SELECT nextval('cm_log_seq') INTO :h_id2;
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 로그 시퀀스 실패"); FAIL(b); }
    snprintf(sbuf, sizeof(sbuf), "RC_DEPGAP scan=%ld match=%ld unmatch=%ld gross=%ld rc=%ld",
             scan_rows, matched_rows, unmatched_rows, h_gross, rc_code);
    strncpy(h_reason, sbuf, sizeof(h_reason)-1); h_reason[sizeof(h_reason)-1] = 0;
    strcpy(h_lvl, rc_code >= 2 ? "E" : (rc_code == 1 ? "W" : "I"));
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (:h_id2, :h_svc, :h_lvl, :h_reason, :h_bizdate);
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 감사 로그 적재 실패 [%d]", sqlca.sqlcode); FAIL(b); }

    /* [7] 집계/요약 재집계부 ------------------------------------------ */
    EXEC SQL SELECT count(*) INTO :h_ucnt FROM purchase p
        WHERE p.biz_date = :h_bizdate
          AND p.status IN ('A','H');
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 미결 재집계 오류"); FAIL(b); }
    EXEC SQL SELECT coalesce(sum(net),0) INTO :h_set FROM settlement WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { userlog("[RC_DEPGAP] 정산 재집계 오류"); FAIL(b); }
    if (h_val == 0) h_val = h_set;
    if (h_n1 == 0) h_n1 = matched_rows;
    if (h_n2 == 0) h_n2 = unmatched_rows;

    /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN -----------------------
     * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다.
     * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가
     * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */
    {
        long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC);
        long ch_pid = getl(b, T_PURCHASE_ID);
        setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net);
        setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows);
        setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt);
        setl(b, T_ARG4, rc_code);
        Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
        if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
        Bchg(b, T_SVCNAME, 0, h_svc, 0L);
        if (unmatched_rows <= 0) {
            userlog("[RC_DEPGAP] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows);
        } else {
            userlog("[RC_DEPGAP] 입금 미도래 구간 검증 연계 -> VL_AXSETTPAY pid=%ld date=[%s]", ch_pid, h_bizdate);
            if (tpcall("VL_AXSETTPAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) {
                userlog("[RC_DEPGAP] tpcall(VL_AXSETTPAY) 실패: %s", tpstrerror(tperrno));
                setl(b, T_RC, 8893); Bchg(b, T_MSG, 0, "입금 미도래 구간 검증 연계 실패", 0L);
                FAIL(b);
            }
            ch_sub = getl(b, T_RC);
            if (ch_sub != 0) userlog("[RC_DEPGAP] VL_AXSETTPAY 이상 회신 rc=%ld", ch_sub);
        }
        setl(b, T_RC, ch_keep);   /* 기존 응답 계약 복원 — [8]에서 최종 확정 */
    }

    /* [8] 응답부 (출력 필드 설정) ------------------------------------- */
    setl(b, T_COUNT, out_cnt);
    /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */

    /* [9] 완료 로깅 --------------------------------------------------- */
    userlog("[RC_DEPGAP] 대사 정상 종료 rc=%ld out=%ld status=%s", rc_code, out_cnt, h_status);
    OK(b);
}

/* vim: set ts=4 sw=4 et smartindent: */
