/*
 * RC_3WAY.pgc - rc 모듈 서비스 RC_3WAY (3자 대사 온라인 프로그램).
 * 업무: 카드망 정산파일(st_net_settlement) ↔ 내부원장(settlement/ledger) ↔
 *       은행실입금(st_funding_instr) 3자 대사. 차이 산출 후 rc_3way UPSERT.
 * 입력: T_BIZDATE(영업일), T_KEY1(member_bin).
 * 출력: T_AMT1=amt_network, T_ARG1=diff_ni, T_STATUS=status, T_RC.
 * 처리단계: 입력검증->망/내부/은행 3자 조회->차이산출->상태판정->rc_3way UPSERT
 *           ->감사적재->응답.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). rc_svr 가 tpsvrinit 에서 광고.
 */
#include "RC_3WAY.h"

/* RC_3WAY - 3자 대사(망·내부·은행) 차이 산출 및 rc_3way UPSERT. */
void RC_3WAY(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    char  bizin[16], binin[64];
    long  diff_ni = 0, diff_nb = 0;   /* 로컬 산출(호스트변수 아님) */
    EXEC SQL BEGIN DECLARE SECTION;
    char  h_bizdate[16], h_bin[64], h_status[16], h_svc[24], h_reason[192];
    long  h_net_amt, h_internal, h_bank, h_diff_ni, h_diff_nb;
    long  h_ncnt, h_icnt, h_bcnt, h_logid;
    EXEC SQL END DECLARE SECTION;

    /* 지역/호스트 변수 초기화 (DECLARE SECTION 밖) */
    h_net_amt = h_internal = h_bank = h_diff_ni = h_diff_nb = 0;
    h_ncnt = h_icnt = h_bcnt = h_logid = 0;
    bizin[0] = binin[0] = 0;
    h_bizdate[0] = h_bin[0] = 0;
    strcpy(h_status, "PENDING");
    strcpy(h_svc, "RC_3WAY");
    strcpy(h_reason, "3WAY_RECON");
    userlog("[RC_3WAY] 3자 대사 진입");

    /* [1] 입력 검증부 -------------------------------------------------- */
    gets_(b, T_BIZDATE, bizin, sizeof(bizin));
    if (strlen(bizin) < 8) {
        setl(b, T_RC, 8001);
        Bchg(b, T_MSG, 0, "영업일자(biz_date) 형식 오류", 0L);
        userlog("[RC_3WAY] 영업일 검증 실패 val=[%s]", bizin);
        FAIL(b);
    }
    strncpy(h_bizdate, bizin, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    gets_(b, T_KEY1, binin, sizeof(binin));
    if (binin[0] == 0) {
        setl(b, T_RC, 8002);
        Bchg(b, T_MSG, 0, "회원사 BIN(member_bin) 필수", 0L);
        userlog("[RC_3WAY] member_bin 미지정");
        FAIL(b);
    }
    strncpy(h_bin, binin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
    userlog("[RC_3WAY] 대사 대상 date=[%s] bin=[%s]", h_bizdate, h_bin);

    /* [2-1] 카드망(st_net_settlement) 순액 조회 — 망 레그 --------------- */
    EXEC SQL SELECT coalesce(sum(net_amt),0), count(*)
        INTO :h_net_amt, :h_ncnt
        FROM st_net_settlement
        WHERE member_bin = :h_bin AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 망 정산 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); }
    if (h_ncnt == 0)
        userlog("[RC_3WAY] 망 정산 데이터 없음 bin=[%s] date=[%s]", h_bin, h_bizdate);

    /* [2-2] 내부 원장(settlement 합, 없으면 ledger SETTLE 합) — 내부 레그
     * 내부원장은 member_bin 키가 없으므로 당일 순액 합으로 근사한다. */
    EXEC SQL SELECT coalesce(sum(net),0), count(*)
        INTO :h_internal, :h_icnt
        FROM settlement WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 정산원장 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); }
    if (h_icnt == 0) {
        EXEC SQL SELECT coalesce(sum(amount),0)
            INTO :h_internal
            FROM ledger WHERE biz_date = :h_bizdate AND entry_type IN ('SETTLE','RECON');
        if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 원장 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); }
        userlog("[RC_3WAY] 내부 레그 ledger 근사 적용 internal=%ld", h_internal);
    }

    /* [2-3] 은행 실입금(st_funding_instr 합) — 은행 레그(근사) ---------- */
    EXEC SQL SELECT coalesce(sum(amount),0), count(*)
        INTO :h_bank, :h_bcnt
        FROM st_funding_instr
        WHERE biz_date = :h_bizdate AND status IN ('SENT','CONFIRMED');
    if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 은행 입금 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); }

    /* [3] 차이 산출부 (diff_ni = 망-내부, diff_nb = 망-은행) ----------- */
    diff_ni = h_net_amt - h_internal;
    diff_nb = h_net_amt - h_bank;
    h_diff_ni = diff_ni;
    h_diff_nb = diff_nb;
    userlog("[RC_3WAY] 산출 net=%ld internal=%ld bank=%ld diff_ni=%ld diff_nb=%ld",
            h_net_amt, h_internal, h_bank, h_diff_ni, h_diff_nb);

    /* [4] 상태 판정부 (차이 0 -> MATCHED, 그 외 -> DIFF, 망無 -> PENDING) */
    if (h_ncnt == 0) {
        strcpy(h_status, "PENDING");
        userlog("[RC_3WAY] 망 데이터 부재 -> PENDING");
    } else if (h_diff_ni == 0 && h_diff_nb == 0) {
        strcpy(h_status, "MATCHED");
    } else {
        strcpy(h_status, "DIFF");
        userlog("[RC_3WAY] 3자 불일치 diff_ni=%ld diff_nb=%ld", h_diff_ni, h_diff_nb);
    }

    /* [5] 본처리부: rc_3way UPSERT (biz_date, member_bin) --------------- */
    EXEC SQL INSERT INTO rc_3way
        (recon_id, biz_date, member_bin, amt_network, amt_internal, amt_bank,
         diff_ni, diff_nb, status)
        VALUES (nextval('rc_3way_seq'), :h_bizdate, :h_bin, :h_net_amt, :h_internal,
                :h_bank, :h_diff_ni, :h_diff_nb, :h_status)
        ON CONFLICT (biz_date, member_bin) DO UPDATE SET
            amt_network  = EXCLUDED.amt_network,
            amt_internal = EXCLUDED.amt_internal,
            amt_bank     = EXCLUDED.amt_bank,
            diff_ni      = EXCLUDED.diff_ni,
            diff_nb      = EXCLUDED.diff_nb,
            status       = EXCLUDED.status;
    if (sqlca.sqlcode < 0) {
        userlog("[RC_3WAY] rc_3way UPSERT 실패 [%d]", sqlca.sqlcode);
        setl(b, T_RC, 8003);
        Bchg(b, T_MSG, 0, "3자대사 결과 적재 실패", 0L);
        FAIL(b);
    }

    /* [6] 이력/감사 적재부 (cm_log) ----------------------------------- */
    EXEC SQL SELECT nextval('cm_log_seq') INTO :h_logid;
    if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 로그 시퀀스 실패"); FAIL(b); }
    snprintf(h_reason, sizeof(h_reason),
        "RC_3WAY bin=%s net=%ld internal=%ld bank=%ld dni=%ld dnb=%ld st=%s",
        h_bin, h_net_amt, h_internal, h_bank, h_diff_ni, h_diff_nb, h_status);
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (:h_logid, :h_svc,
                CASE WHEN :h_diff_ni = 0 AND :h_diff_nb = 0 THEN 'I' ELSE 'W' END,
                :h_reason, :h_bizdate);
    if (sqlca.sqlcode < 0) { userlog("[RC_3WAY] 감사 로그 적재 실패 [%d]", sqlca.sqlcode); FAIL(b); }

    /* [7] 응답부 (출력 필드 설정) ------------------------------------- */
    setl(b, T_AMT1, h_net_amt);   /* 카드망 순액 */
    setl(b, T_ARG1, h_diff_ni);   /* 망-내부 차이 */
    setl(b, T_AMT2, h_diff_nb);   /* 망-은행 차이(참조) */
    Bchg(b, T_STATUS, 0, h_status, 0L);
    setl(b, T_RC, 0);

    /* [8] 완료 로깅 --------------------------------------------------- */
    userlog("[RC_3WAY] 3자 대사 종료 bin=[%s] status=%s diff_ni=%ld",
            h_bin, h_status, h_diff_ni);
    OK(b);
}

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