/*
 * PAY_LEDGERSUM.pgc - py (지급) 모듈 온라인 서비스 PAY_LEDGERSUM.
 * 지급원장 유형별 합계: 당일 py_ledger 를 기표유형별 커서 집계해
 * 유형/건수/합계/최소/최대를 occurrence 로 회신한다 (원장 마감 검산용).
 * 처리 구성: 입력검증 -> 마스터/정책 조회 -> 업무규칙 분기 -> 본처리 ->
 *            감사이력 적재 -> 집계 갱신 -> 예외보상 -> 응답 -> 로깅 [cursor].
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by py_svr.
 */
#include "PAY_LEDGERSUM.h"

void PAY_LEDGERSUM(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    int gi = 0;
    long tot_cnt = 0, tot_sum = 0, tot_fee = 0, top_cnt = 0, top_sum = 0;
    char top_grp[64];
    EXEC SQL BEGIN DECLARE SECTION;
    char h_bizdate[64];
    char h_wgrp[64];
    long h_wgcnt;
    long h_wgsum;
    long h_wgfee;
    long h_wtot;
    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) 입력 검증부 - 모든 입력 필드의 필수/범위/형식 검사 */
    gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
    if (strlen(h_bizdate) != 10) {
        setl(b, T_RC, 11);
        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;
    top_grp[0] = 0;
    /* 2) 사전 규모 확인 - 커서 오픈 전 총건수 파악 */
    EXEC SQL SELECT count(*) INTO :h_wtot FROM py_ledger l WHERE l.biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 40);
        Bchg(b, T_MSG, 0, "집계 사전 조회 실패", 0L);
        FAIL(b);
    }
    userlog("PAY_LEDGERSUM 집계 시작: 기준일=%s 대상=%ld건 (기표유형별)", h_wdate, h_wtot);
    /* 커서 정의: 기표유형별 건수/금액 집계 */
    EXEC SQL DECLARE cur_pay_ledgersum CURSOR FOR
        SELECT l.entry_type, count(*), coalesce(sum(l.amount),0), 0
        FROM py_ledger l WHERE l.biz_date = :h_bizdate
        GROUP BY l.entry_type ORDER BY 2 DESC, 1;
    EXEC SQL OPEN cur_pay_ledgersum;
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 41);
        Bchg(b, T_MSG, 0, "집계 커서 OPEN 실패", 0L);
        FAIL(b);
    }
    /* 3) 본처리부 - 커서 순회하며 그룹별 집계/상위 추출 */
    for (;;) {
        EXEC SQL FETCH cur_pay_ledgersum INTO :h_wgrp, :h_wgcnt, :h_wgsum, :h_wgfee;
        if (sqlca.sqlcode == 100) break;
        if (sqlca.sqlcode < 0) {
            EXEC SQL CLOSE cur_pay_ledgersum;
            setl(b, T_RC, 42); Bchg(b, T_MSG, 0, "집계 FETCH 오류", 0L); FAIL(b);
        }
        tot_cnt += h_wgcnt;
        tot_sum += h_wgsum;
        tot_fee += h_wgfee;
        if (h_wgcnt > top_cnt) {
            top_cnt = h_wgcnt;
            top_sum = h_wgsum;
            strncpy(top_grp, h_wgrp, sizeof(top_grp)-1);
            top_grp[sizeof(top_grp)-1] = 0;
        }
        if (gi < 10) {
            Bchg(b, T_STR1, gi, h_wgrp, 0L);
            Bchg(b, T_AMT1, gi, (char *)&h_wgsum, 0L);
            Bchg(b, T_ARG1, gi, (char *)&h_wgcnt, 0L);
            gi++;
        }
    }
    EXEC SQL CLOSE cur_pay_ledgersum;
    strcpy(h_pval, "5000");
    EXEC SQL SELECT coalesce(param_val, :h_pval) INTO :h_pval
        FROM cm_param WHERE param_key = 'pay_ledgersum_concentration';
    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 = 5000;
    /* 업무규칙 분기부 - 분포 집중도 판정 (3분기) */
    if (gi == 0) {
        setl(b, T_RC, 1); Bchg(b, T_MSG, 0, "기표유형별 집계 대상 없음", 0L);
    } else if (tot_cnt > 0 && top_cnt * 10000 / tot_cnt > h_thr) {
        setl(b, T_RC, 0); Bchg(b, T_MSG, 0, "특정 기표유형 집중 - 확인 필요", 0L);
    } else {
        setl(b, T_RC, 0); Bchg(b, T_MSG, 0, "기표유형별 정상 분포", 0L);
    }
    strcpy(h_lvl, "I");
    snprintf(h_amsg, sizeof(h_amsg), "%s %s별 그룹=%d 건수=%ld 금액=%ld 최다=%s", "PAY_LEDGERSUM", "기표유형", gi, tot_cnt, tot_sum, top_grp);
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), 'PAY_LEDGERSUM', :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);
    }
    /* 8) 응답부 */
    setl(b, T_COUNT, tot_cnt);
    setl(b, T_GROSS, tot_sum);
    setl(b, T_AMT2, top_sum);
    setl(b, T_AMT3, top_sum);
    userlog("PAY_LEDGERSUM 완료: 그룹=%d 총건=%ld 총액=%ld 최다=%s",
            gi, tot_cnt, tot_sum, top_grp);
    /* 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_LEDGERSUM", h_wz3, h_wz1);
    }
    if (h_wz2 < 0) {
        setl(b, T_RC, 93);
        Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L);
        FAIL(b);
    }
    OK(b);
}
