/*
 * ACQ_AMTFIX.pgc - ac 모듈 서비스 ACQ_AMTFIX (one service = one file).
 * 금액 확정 정정: 직전 금액을 조회한 뒤 하우스 기준 MDR 로 수수료를 절대
 * 재계산하고 증감(delta)을 회신한다.
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
 */
#include "ACQ_AMTFIX.h"

void ACQ_AMTFIX(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    const char *SVC = "ACQ_AMTFIX";
    char merch[64], bizdate[16], ccy[8], issuer[32], channel[16], logmsg[256];
    char reason[128], docno[64];
    long threshold = 0, ratio = 0, k = 0;
    char category[24];
    long i = 0, bps = 25, computed = 0, prior = 0;
    EXEC SQL BEGIN DECLARE SECTION;
    long h_cnt = 0, h_gross = 0, h_net = 0, h_fee = 0, h_sum = 0, h_avg = 0, h_max = 0;
    long h_a = 0, h_b = 0, h_c = 0, h_d = 0, h_e = 0, h_top = 0, h_val = 0, h_val2 = 0;
    long h_lim = 0, h_rate = 0, h_pid = 0, h_amt = 0, h_logid = 0, h_n = 0, h_id = 0;
    long h_openc = 0, h_setc = 0, h_pdgross = 0, h_ctx = 0, h_share = 0, h_min = 0;
    long h_supply = 0, h_vat = 0, h_months = 0, h_delta = 0, h_tax = 0;
    char h_merch[64], h_bizdate[16], h_ccy[8], h_issuer[32], h_status[8], h_chan[16];
    char h_reason[128], h_str1[64], h_str2[40], h_logmsg[256], h_d1[16], h_d2[16];
    long h_krw = 0, h_fx = 0, h_comp = 0, h_rate2 = 0, h_sfee = 0, h_snet = 0;
    long h_seq = 0, h_mamt = 0, h_new = 0, h_aff = 0, h_prev2 = 0;
    long h_canid = 0, h_adjid = 0, h_invid = 0, h_ledid = 0, h_setid = 0, h_rem = 0;
    char h_prev[8], h_ctype[16], h_category[24], h_docno[64];
    EXEC SQL END DECLARE SECTION;

    /* 작업영역 초기화: 문자열 호스트변수/로컬버퍼를 모두 널로 시작한다 */
    memset(h_merch, 0, sizeof(h_merch));   memset(h_bizdate, 0, sizeof(h_bizdate));
    memset(h_ccy, 0, sizeof(h_ccy));       memset(h_issuer, 0, sizeof(h_issuer));
    memset(h_status, 0, sizeof(h_status)); memset(h_chan, 0, sizeof(h_chan));
    memset(h_reason, 0, sizeof(h_reason)); memset(h_str1, 0, sizeof(h_str1));
    memset(h_str2, 0, sizeof(h_str2));     memset(h_logmsg, 0, sizeof(h_logmsg));
    memset(h_d1, 0, sizeof(h_d1));         memset(h_d2, 0, sizeof(h_d2));
    memset(merch, 0, sizeof(merch));       memset(bizdate, 0, sizeof(bizdate));
    memset(ccy, 0, sizeof(ccy));           memset(issuer, 0, sizeof(issuer));
    memset(channel, 0, sizeof(channel));   memset(reason, 0, sizeof(reason));
    memset(docno, 0, sizeof(docno));       memset(logmsg, 0, sizeof(logmsg));
    memset(h_prev, 0, sizeof(h_prev));     memset(h_ctype, 0, sizeof(h_ctype));
    memset(h_category, 0, sizeof(h_category)); memset(h_docno, 0, sizeof(h_docno));
    memset(category, 0, sizeof(category));

    userlog("%s 진입: 매입 금액/수수료 조정 요청", SVC);

    /* 1) 입력 검증부: 전 필드 필수/범위/형식 점검 후 위반 시 거절 */
    h_pid = getl(b, T_PURCHASE_ID);
    if (h_pid <= 0) { Bchg(b, T_MSG, 0, "매입 ID 오류", 0L); setl(b, T_RC, 102); FAIL(b); }
    h_amt = getl(b, T_AMOUNT);
    if (h_amt < 1L) { Bchg(b, T_MSG, 0, "금액 범위 오류", 0L); setl(b, T_RC, 104); FAIL(b); }
    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    if (h_bizdate[0] == 0) {
        EXEC SQL SELECT param_val INTO :h_bizdate FROM cm_param WHERE param_key = 'BIZ_DATE';
        if (sqlca.sqlcode != 0) strcpy(h_bizdate, "2026-07-19");
    }
    if (strlen(h_bizdate) != 10) { Bchg(b, T_MSG, 0, "영업일 형식 오류", 0L); setl(b, T_RC, 105); FAIL(b); }
    userlog("%s 컨텍스트: pid=%ld merch=%s amt=%ld bizdate=%s", SVC, h_pid, h_merch, h_amt, h_bizdate);
    /* 요청 파라미터 감사 덤프 (운영 추적용) */
    userlog("%s 요청감사: 갱신 요청 수신", SVC);
    userlog("%s 요청감사: merch=%s pid=%ld amt=%ld biz=%s", SVC, h_merch, h_pid, h_amt, h_bizdate);

    /* 2) 마스터/정책/상태 조회부 */
    EXEC SQL SELECT status, merchant_id, amount, fee, net INTO :h_prev, :h_merch, :h_gross, :h_fee, :h_net FROM purchase WHERE purchase_id = :h_pid;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 매입원장 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    if (sqlca.sqlcode == 100) { Bchg(b, T_MSG, 0, "매입 미존재", 0L); setl(b, T_RC, 111); FAIL(b); }
    userlog("%s 원매입: pid=%ld status=%s amount=%ld", SVC, h_pid, h_prev, h_gross);
    EXEC SQL SELECT status, daily_limit INTO :h_status, :h_lim FROM merchant WHERE merchant_id = :h_merch;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 가맹점마스터 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    if (sqlca.sqlcode == 100) { Bchg(b, T_MSG, 0, "가맹점 미존재", 0L); setl(b, T_RC, 110); FAIL(b); }
    if (acdb_merchant_mdr(h_merch, &h_rate) < 0) h_rate = 25;

    /* 3) 업무규칙 분기부: 조정 유형/부호/한도 판정(3+ 분기) */
    /* 확정 금액과 기존 금액의 증감 방향으로 처리 경로를 나눈다 */
    h_delta = h_amt - h_gross;
    if (h_delta == 0) { Bchg(b, T_MSG, 0, "금액 변동 없음", 0L); setl(b, T_RC, 169); FAIL(b); }
    else if (h_delta > 0) { h_val = 3; Bchg(b, T_MSG, 0, "금액 증액 확정", 0L); }
    else { h_val = 2; Bchg(b, T_MSG, 0, "금액 감액 확정", 0L); }
    /* 하우스 기준 25bps 로 절대 재계산 */
    computed = acq_fee(h_amt, 25);

    /* 4) 본처리부: 조정 원장 기록 및 매입 금액 보정 */
    h_fee = computed;
    h_net = h_amt - h_fee;
    if (acdb_update_amount(h_pid, h_amt, h_fee, h_net) < 0)
        { Bchg(b, T_MSG, 0, "금액 갱신 실패", 0L); setl(b, T_RC, 97); FAIL(b); }
    h_aff = 1;

    /* 6) 집계/요약 갱신부 */
    EXEC SQL SELECT count(*), coalesce(sum(amount),0), coalesce(sum(fee),0), coalesce(sum(net),0) INTO :h_cnt, :h_sum, :h_sfee, :h_snet FROM purchase WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 재집계 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    /* 재집계 결과(총액/수수료/순액/건수)를 가맹점 일별 요약에 반영 */
    if (acdb_upsert_merch_sum(h_merch, h_bizdate, h_sum, h_sfee, h_snet, h_cnt) < 0)
        userlog("%s 주의: 요약 갱신 스킵", SVC);
    userlog("%s 요약갱신: merch=%s 건수=%ld 총액=%ld 수수료=%ld", SVC, h_merch, h_cnt, h_sum, h_sfee);

    /* 7) 예외/보상부: 반영 결과 정합 확인 */
    if (h_aff < 0) { Bchg(b, T_MSG, 0, "반영 실패", 0L); setl(b, T_RC, 92); FAIL(b); }

    /* 5) 이력/감사 적재부: 처리 요약을 공통 로그(cm_log)에 남긴다 */
    snprintf(logmsg, sizeof(logmsg), "금액확정 pid=%ld %ld -> %ld 증감=%ld", h_pid, h_gross, h_amt, h_delta);
    strncpy(h_logmsg, logmsg, sizeof(h_logmsg)-1); h_logmsg[sizeof(h_logmsg)-1] = 0;
    EXEC SQL SELECT nextval('cm_log_seq') INTO :h_logid;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 로그채번 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (:h_logid, 'ACQ_AMTFIX', 'I', :h_logmsg, :h_bizdate);
    if (sqlca.sqlcode < 0) {
        userlog("%s: 로그적재 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }

    /* 9) 사후 검증부: 당일 처리 이력 자기 점검 및 과다 호출 감시 */
    EXEC SQL SELECT count(*) INTO :h_ctx FROM cm_log
        WHERE svc_name = 'ACQ_AMTFIX' AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 사후검증 SQL 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    if (h_ctx <= 0) {
        userlog("%s 경보: 처리 이력이 적재되지 않음", SVC);
        Bchg(b, T_MSG, 0, "이력 적재 확인 실패", 0L);
        setl(b, T_RC, 89); FAIL(b);
    }
    if (h_ctx > 1000)
        userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
    setl(b, T_ARG6, h_ctx);

    /* --- 업무 체인: 금액 보정 -> 금액 검증(VL_AMOUNT) ---
     * 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
     * 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
     * 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
     * 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
    {
        long rlen = 0, chain_rc = 0;
        char keep_status[16];

        keep_status[0] = 0;
        gets_(b, T_STATUS, keep_status, sizeof(keep_status));
        Bchg(b, T_SVCNAME, 0, "ACQ_AMTFIX", 0L);
        setl(b, T_PURCHASE_ID, h_pid);
        setl(b, T_AMOUNT, h_amt);
        Bchg(b, T_MERCHANT, 0, h_merch, 0L);
        Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);

        /* 1단계: 보정 후 금액이 허용 오차 안인지 검증계에서 확인한다 */
        setl(b, T_AMT1, h_gross);
        setl(b, T_DELTA, h_delta);
        if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
            userlog("%s: tpcall(VL_AMOUNT) 실패: %s", SVC, tpstrerror(tperrno));
            Bchg(b, T_MSG, 0, "보정 금액 검증 실패", 0L); setl(b, T_RC, 531);
            FAIL(b);
        }
        chain_rc = getl(b, T_RC);
        userlog("%s 체인: VL_AMOUNT 응답 rc=%ld", SVC, chain_rc);

        /* 하위가 덮어쓴 자기 상태 계약값 복원 */
        if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
        setl(b, T_RC, 0);
    }

    /* 8) 응답부 */
    setl(b, T_AMOUNT, h_amt);
    setl(b, T_DELTA, h_delta);
    setl(b, T_FEE, h_fee);
    setl(b, T_NET, h_net);
    setl(b, T_ARG1, h_val);
    userlog("%s 완료: pid=%ld 반영=%ld", SVC, h_pid, h_aff);
    setl(b, T_RC, 0);
    OK(b);
}
