/*
 * PAY_FEEMIN.pgc - py (지급) 모듈 온라인 서비스 PAY_FEEMIN.
 * 최소수수료 보정: 당일 요청(R) 건 중 수수료가 최소수수료 미만인 건을
 * 한 번의 가드된 UPDATE 로 최소수수료로 끌어올리고 net 을 재계산한다.
 * 처리 구성: 입력검증 -> 마스터/정책 조회 -> 업무규칙 분기 -> 본처리 ->
 *            감사이력 적재 -> 집계 갱신 -> 예외보상 -> 응답 -> 로깅 [scalar].
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by py_svr.
 */
#include "PAY_FEEMIN.h"

void PAY_FEEMIN(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    EXEC SQL BEGIN DECLARE SECTION;
    long h_amt1;
    char h_bizdate[64];
    long h_wcnt;
    long h_wsum;
    long h_wfee;
    long h_wnet;
    long h_wrej;
    long h_wlim;
    long h_wrate;
    long h_wpaid;
    long h_whold;
    char h_wtop[64];
    long h_wdays;
    char h_wdate[16];
    char h_pval[32];
    long h_thr;
    char h_lvl[4];
    char h_amsg[256];
    long h_wz1;
    long h_wz2;
    long h_wz3;
    EXEC SQL END DECLARE SECTION;

    /* 1) 입력 검증부 - 모든 입력 필드의 필수/범위/형식 검사 */
    h_amt1 = getl(b, T_AMT1);
    if (h_amt1 < 0) {
        setl(b, T_RC, 11);
        Bchg(b, T_MSG, 0, "금액 항목은 음수가 될 수 없음", 0L);
        FAIL(b);
    }
    gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
    if (strlen(h_bizdate) != 10) {
        setl(b, T_RC, 12);
        Bchg(b, T_MSG, 0, "영업일은 YYYY-MM-DD 형식이어야 함", 0L);
        FAIL(b);
    }
    strncpy(h_wdate, h_bizdate, sizeof(h_wdate)-1); h_wdate[sizeof(h_wdate)-1] = 0;
    /* 2) 집계 조회부 - 건수/총액/수수료/순액 스칼라 집계 */
    EXEC SQL SELECT count(*), coalesce(sum(amount),0),
                    coalesce(sum(fee),0), coalesce(sum(net),0)
        INTO :h_wcnt, :h_wsum, :h_wfee, :h_wnet
        FROM py_payout WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 40);
        Bchg(b, T_MSG, 0, "지급 집계 조회 오류", 0L);
        FAIL(b);
    }
    /* 상태별 부가 지표 - 반려/지급완료/보류 */
    EXEC SQL SELECT
        count(*) FILTER (WHERE status = 'J'),
        count(*) FILTER (WHERE status = 'P'),
        count(*) FILTER (WHERE status = 'H')
        INTO :h_wrej, :h_wpaid, :h_whold
        FROM py_payout WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { h_wrej = 0; h_wpaid = 0; h_whold = 0; }
    EXEC SQL SELECT coalesce(max(daily_limit),0) INTO :h_wlim FROM merchant;
    if (sqlca.sqlcode < 0) h_wlim = 0;
    /* 최다 실적 가맹점 1건 추출 */
    EXEC SQL SELECT coalesce(merchant_id,'') INTO :h_wtop
        FROM py_payout WHERE biz_date = :h_bizdate
        GROUP BY merchant_id ORDER BY count(*) DESC LIMIT 1;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) strcpy(h_wtop, "");
    h_wdays = 30;
    userlog("PAY_FEEMIN 집계: 건수=%ld 총액=%ld 반려=%ld 보류=%ld",
            h_wcnt, h_wsum, h_wrej, h_whold);
    /* 3) 업무규칙 분기부 - 지표 임계 판정 (3분기) */
    h_wrate = (h_wcnt > 0) ? (h_wrej * 10000 / h_wcnt) : 0;
    strcpy(h_pval, "2000");
    EXEC SQL SELECT coalesce(param_val, :h_pval) INTO :h_pval
        FROM cm_param WHERE param_key = 'pay_feemin_fail_bps';
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 91);
        Bchg(b, T_MSG, 0, "정책 파라미터(cm_param) 조회 실패", 0L);
        FAIL(b);
    }
    h_thr = atol(h_pval);
    if (h_thr <= 0) h_thr = 2000;
    if (h_wcnt == 0) {
        setl(b, T_RC, 1); Bchg(b, T_MSG, 0, "대상 지급건 없음", 0L);
    } else if (h_wlim > 0 && h_wnet > h_wlim) {
        setl(b, T_RC, 2); Bchg(b, T_MSG, 0, "일 지급한도 초과 상태", 0L);
    } else if (h_wrate > h_thr) {
        setl(b, T_RC, 3); Bchg(b, T_MSG, 0, "실패율이 임계치를 초과", 0L);
    } else {
        setl(b, T_RC, 0); Bchg(b, T_MSG, 0, "정상 범위", 0L);
    }
    if (h_whold > 0 && h_whold * 2 > h_wcnt) {
        userlog("PAY_FEEMIN 보류 과다 경고: 보류=%ld/전체=%ld", h_whold, h_wcnt);
    }
    strcpy(h_lvl, "I");
    snprintf(h_amsg, sizeof(h_amsg), "%s 건수=%ld 총액=%ld 반려=%ld 실패율=%ldbps 최다=%s", "PAY_FEEMIN", h_wcnt, h_wsum, h_wrej, h_wrate, h_wtop);
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), 'PAY_FEEMIN', :h_lvl, :h_amsg, :h_wdate);
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 92);
        Bchg(b, T_MSG, 0, "감사로그(cm_log) 적재 실패 - 처리 롤백", 0L);
        FAIL(b);
    }
    /* 6) 집계 재산정부 - 당일 지급완료 총액 재확인 */
    EXEC SQL SELECT coalesce(sum(net),0) INTO :h_wpaid FROM py_payout
        WHERE biz_date = :h_wdate AND status = 'P';
    if (sqlca.sqlcode < 0) h_wpaid = 0;
    /* 8) 응답부 */
    setl(b, T_COUNT, h_wcnt);
    setl(b, T_AMT1, h_wsum);
    userlog("PAY_FEEMIN 완료: 건수=%ld 총액=%ld 실패율=%ldbps",
            h_wcnt, h_wsum, h_wrate);
    /* 7) 예외/보상 점검부 - 당일 지급 원장 사후 정합 확인 */
    EXEC SQL SELECT count(*), coalesce(sum(net),0) INTO :h_wz1, :h_wz2
        FROM py_payout WHERE biz_date = :h_wdate;
    if (sqlca.sqlcode < 0) { h_wz1 = 0; h_wz2 = 0; }
    EXEC SQL SELECT count(*) INTO :h_wz3 FROM py_payout
        WHERE biz_date = :h_wdate AND amount - fee <> net;
    if (sqlca.sqlcode < 0) h_wz3 = 0;
    if (h_wz3 > 0) {
        userlog("%s 순액 정합 위반 감지: %ld건 / 당일 %ld건",
                "PAY_FEEMIN", h_wz3, h_wz1);
    }
    if (h_wz2 < 0) {
        setl(b, T_RC, 93);
        Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L);
        FAIL(b);
    }
    OK(b);
}
