/*
 * PAY_GARNISH.pgc - py (지급) 모듈 온라인 서비스 PAY_GARNISH.
 * 가압류 등록: 활성 계좌를 GARNISH 로 표시하고, 그 계좌 미지급(R/A) 잔액을
 * 집계해 가압류 채권으로 py_ledger 에 음수 GARNISH 기표를 남긴다.
 * 처리 구성: 입력검증 -> 마스터/정책 조회 -> 업무규칙 분기 -> 본처리 ->
 *            감사이력 적재 -> 집계 갱신 -> 예외보상 -> 응답 -> 로깅 [acct].
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by py_svr.
 */
#include "PAY_GARNISH.h"

void PAY_GARNISH(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    EXEC SQL BEGIN DECLARE SECTION;
    char h_bizdate[64];
    char h_key1[64];
    char h_wast[16];
    long h_wbal;
    char h_wholder[64];
    char h_wmerch[64];
    long h_waff;
    long h_wcas;
    long h_wsum;
    long h_wcnt;
    char h_wacct[64];
    char h_wdate[16];
    char h_pval[32];
    long h_thr;
    char h_lvl[4];
    char h_amsg[256];
    long h_wa1;
    long h_wa2;
    long h_wa3;
    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);
    }
    gets_(b, T_KEY1, h_key1, sizeof(h_key1));
    if (h_key1[0] == 0 || strlen(h_key1) < 3) {
        setl(b, T_RC, 12);
        Bchg(b, T_MSG, 0, "계좌번호/키 값이 유효하지 않음", 0L);
        FAIL(b);
    }
    /* 2) 마스터 조회부 - 대상 지급계좌 확정 후 상태/잔액/예금주 조회 */
    strncpy(h_wacct, h_key1, sizeof(h_wacct)-1);
    h_wacct[sizeof(h_wacct)-1] = 0;
    EXEC SQL SELECT status, balance, holder, merchant_id
        INTO :h_wast, :h_wbal, :h_wholder, :h_wmerch
        FROM py_account WHERE account_no = :h_wacct;
    if (sqlca.sqlcode == 100) {
        setl(b, T_RC, 40);
        Bchg(b, T_MSG, 0, "대상 지급계좌가 등록되어 있지 않음", 0L);
        FAIL(b);
    }
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 41);
        Bchg(b, T_MSG, 0, "지급계좌 조회 중 DB 오류", 0L);
        FAIL(b);
    }
    /* 해당 계좌의 미지급 잔액 규모 파악 */
    EXEC SQL SELECT count(*), coalesce(sum(net),0) INTO :h_wcnt, :h_wsum
        FROM py_payout WHERE account_no = :h_wacct AND status IN ('R','A','H');
    if (sqlca.sqlcode < 0) { h_wcnt = 0; h_wsum = 0; }
    strncpy(h_wdate, h_bizdate, sizeof(h_wdate)-1); h_wdate[sizeof(h_wdate)-1] = 0;
    userlog("PAY_GARNISH 진입: acct=%s status=%s bal=%ld 미지급=%ld건",
            h_wacct, h_wast, h_wbal, h_wcnt);
    /* 3) 업무규칙 분기부 - 계좌 상태 전이 적법성 (3분기) */
    if (strcmp(h_wast, "GARNISH") == 0) {
        setl(b, T_RC, 42);
        Bchg(b, T_MSG, 0, "이미 가압류 등록 상태인 계좌", 0L);
        FAIL(b);
    }
    if (strcmp(h_wast, "ACTIVE") != 0) {
        setl(b, T_RC, 43); Bchg(b, T_STATUS, 0, h_wast, 0L);
        Bchg(b, T_MSG, 0, "현재 계좌 상태에서는 가압류 등록 처리 불가", 0L); FAIL(b);
    }
    if (h_wbal < 0) {
        setl(b, T_RC, 44);
        Bchg(b, T_MSG, 0, "잔액이 음수인 비정상 계좌 - 선행 정산 필요", 0L);
        FAIL(b);
    }
    strcpy(h_pval, "1");
    EXEC SQL SELECT coalesce(param_val, :h_pval) INTO :h_pval
        FROM cm_param WHERE param_key = 'pay_garnish_cascade';
    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 = 1;
    /* 4) 본처리부 - 계좌 상태 전이 후 미지급건 연쇄 처리 */
    EXEC SQL UPDATE py_account SET status = 'GARNISH', updated_at = now()
        WHERE account_no = :h_wacct AND status = 'ACTIVE';
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 50);
        Bchg(b, T_MSG, 0, "가압류 등록 처리 실패", 0L);
        FAIL(b);
    }
    h_waff = sqlca.sqlerrd[2];
    if (h_waff == 0) {
        setl(b, T_RC, 4);
        Bchg(b, T_MSG, 0, "계좌 상태 동시성 충돌", 0L);
        FAIL(b);
    }
    EXEC SQL UPDATE py_payout SET status = 'H', reject_reason = '가압류',
            updated_at = now()
        WHERE account_no = :h_wacct AND status IN ('R','A') AND :h_thr > 0;
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 51);
        Bchg(b, T_MSG, 0, "미지급건 연쇄 처리 실패", 0L);
        FAIL(b);
    }
    h_wcas = sqlca.sqlerrd[2];
    strcpy(h_lvl, "W");
    snprintf(h_amsg, sizeof(h_amsg), "%s acct=%s %s->%s 연쇄=%ld 금액=%ld", "PAY_GARNISH", h_wacct, "ACTIVE", "GARNISH", h_wcas, h_wsum);
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), 'PAY_GARNISH', :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 count(*), coalesce(sum(net),0) INTO :h_wa1, :h_wa2
        FROM py_payout WHERE account_no = :h_wacct AND status = 'H';
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 61);
        Bchg(b, T_MSG, 0, "계좌 잔여 미지급 재집계 실패", 0L);
        FAIL(b);
    }
    EXEC SQL SELECT count(*) INTO :h_wa3 FROM py_payout
        WHERE account_no = :h_wacct AND status IN ('R','A');
    if (sqlca.sqlcode < 0) h_wa3 = 0;
    if (h_wa1 > 0 && h_wa3 > h_wa1) {
        userlog("%s 연쇄 처리 후 잔여 존재: 기준=%ld 실적=%ld", "PAY_GARNISH", h_wa1, h_wa3);
    }
    /* 8) 응답부 */
    setl(b, T_RC, 0);
    Bchg(b, T_STATUS, 0, "GARNISH", 0L);
    setl(b, T_COUNT, h_wcas);
    setl(b, T_GROSS, h_wsum);
    Bchg(b, T_MSG, 0, "가압류 등록 및 미지급건 연쇄처리 완료", 0L);
    userlog("PAY_GARNISH 완료: acct=%s 연쇄처리=%ld건 보류금액=%ld",
            h_wacct, h_wcas, h_wsum);
    /* 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_GARNISH", h_wz3, h_wz1);
    }
    if (h_wz2 < 0) {
        setl(b, T_RC, 93);
        Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L);
        FAIL(b);
    }
    OK(b);
}
