/*
 * PAY_ADVANCE.pgc - py (지급) 모듈 온라인 서비스 PAY_ADVANCE.
 * 선지급(advance): 선지급 수수료(1%)를 공제한 지급건(ADVANCE 채널)을 생성.
 * 처리 구성: 입력검증 -> 마스터/정책 조회 -> 업무규칙 분기 -> 본처리 ->
 *            감사이력 적재 -> 집계 갱신 -> 예외보상 -> 응답 -> 로깅 [mkpay].
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by py_svr.
 */
#include "PAY_ADVANCE.h"

void PAY_ADVANCE(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    int gi;
    EXEC SQL BEGIN DECLARE SECTION;
    long h_amount;
    char h_bizdate[64];
    char h_key1[64];
    char h_merchant[64];
    long h_wmdr;
    char h_wmst[16];
    long h_wlim;
    char h_wast[16];
    long h_wbal;
    long h_wfee;
    long h_wnet;
    long h_wpart;
    long h_wnum;
    long h_wid;
    long h_wlast;
    long h_wused;
    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) 입력 검증부 - 모든 입력 필드의 필수/범위/형식 검사 */
    h_amount = getl(b, T_AMOUNT);
    if (h_amount < 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);
    }
    gets_(b, T_KEY1, h_key1, sizeof(h_key1));
    if (h_key1[0] == 0 || strlen(h_key1) < 3) {
        setl(b, T_RC, 13);
        Bchg(b, T_MSG, 0, "계좌번호/키 값이 유효하지 않음", 0L);
        FAIL(b);
    }
    gets_(b, T_MERCHANT, h_merchant, sizeof(h_merchant));
    if (h_merchant[0] == 0) {
        setl(b, T_RC, 14);
        Bchg(b, T_MSG, 0, "가맹점 ID는 필수 입력", 0L);
        FAIL(b);
    }
    /* 2) 마스터 조회부 - 가맹점 계약요율/상태/일한도 */
    EXEC SQL SELECT mdr_bps, status, daily_limit INTO :h_wmdr, :h_wmst, :h_wlim
        FROM merchant WHERE merchant_id = :h_merchant;
    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, "가맹점 마스터 조회 오류", 0L);
        FAIL(b);
    }
    if (strcmp(h_wmst, "ACTIVE") != 0) {
        setl(b, T_RC, 42);
        Bchg(b, T_MSG, 0, "비활성/폐업 가맹점은 지급 생성 불가", 0L);
        FAIL(b);
    }
    /* 지급계좌 상태/잔액 확인 */
    EXEC SQL SELECT status, balance INTO :h_wast, :h_wbal
        FROM py_account WHERE account_no = :h_key1;
    if (sqlca.sqlcode == 100) {
        setl(b, T_RC, 43);
        Bchg(b, T_MSG, 0, "지급계좌 미등록", 0L);
        FAIL(b);
    }
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 44);
        Bchg(b, T_MSG, 0, "지급계좌 조회 오류", 0L);
        FAIL(b);
    }
    if (strcmp(h_wast, "ACTIVE") != 0) {
        setl(b, T_RC, 45);
        Bchg(b, T_MSG, 0, "정상 상태 계좌가 아니어서 지급 불가", 0L);
        FAIL(b);
    }
    /* 당일 기 사용액 조회 - 일한도 통제용 */
    EXEC SQL SELECT coalesce(sum(net),0) INTO :h_wused FROM py_payout
        WHERE merchant_id = :h_merchant AND biz_date = :h_bizdate
          AND status IN ('A','F','P');
    if (sqlca.sqlcode < 0) h_wused = 0;
    strncpy(h_wdate, h_bizdate, sizeof(h_wdate)-1); h_wdate[sizeof(h_wdate)-1] = 0;
    userlog("PAY_ADVANCE 진입: merch=%s amt=%ld mdr=%ldbps 기사용=%ld",
            h_merchant, h_amount, h_wmdr, h_wused);
    /* 3) 업무규칙 분기부 - 금액 구간별 수수료 산정 (3분기) */
    if (h_amount < 100000) {
        h_wfee = acq_fee(h_amount, 100);
    } else if (h_amount < 10000000) {
        h_wfee = acq_fee(h_amount, 100) + acq_vat(acq_fee(h_amount, 100));
    } else {
        h_wfee = acq_fee(h_amount, 100 + 20) + acq_vat(acq_fee(h_amount, 100));
    }
    if (h_wfee < 0) h_wfee = 0;
    h_wnet = h_amount - h_wfee;
    if (h_wnet < 0) h_wnet = 0;
    /* 일한도 통제 */
    if (h_wlim > 0 && h_wused + h_wnet > h_wlim) {
        setl(b, T_RC, 8);
        Bchg(b, T_MSG, 0, "가맹점 일 지급한도 초과", 0L);
        FAIL(b);
    }
    strcpy(h_pval, "500000000");
    EXEC SQL SELECT coalesce(param_val, :h_pval) INTO :h_pval
        FROM cm_param WHERE param_key = 'pay_advance_single_max';
    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 = 500000000;
    if (h_amount > h_thr) {
        setl(b, T_RC, 9);
        Bchg(b, T_MSG, 0, "1건 지급 상한 정책 초과", 0L);
        FAIL(b);
    }
    h_wnum = 1;
    h_wpart = h_amount;
    /* 4) 본처리부 - 지급건 생성 (분할 시 반복 채번) */
    h_wlast = 0;
    for (gi = 0; gi < (int)h_wnum; gi++) {
        EXEC SQL SELECT nextval('py_payout_seq') INTO :h_wid;
        if (sqlca.sqlcode < 0) {
            setl(b, T_RC, 50); Bchg(b, T_MSG, 0, "지급 일련번호 채번 실패", 0L); FAIL(b);
        }
        EXEC SQL INSERT INTO py_payout
            (payout_id, merchant_id, account_no, amount, fee, net,
             status, channel, biz_date)
            VALUES (:h_wid, :h_merchant, :h_key1, :h_wpart, :h_wfee,
                    :h_wpart, 'R', 'ADVANCE', :h_bizdate);
        if (sqlca.sqlcode < 0) {
            setl(b, T_RC, 51); Bchg(b, T_MSG, 0, "지급건 생성 INSERT 실패", 0L); FAIL(b);
        }
        h_wlast = h_wid;
    }
    strcpy(h_lvl, "I");
    snprintf(h_amsg, sizeof(h_amsg), "%s merch=%s 생성=%ld건 총액=%ld 수수료=%ld", "PAY_ADVANCE", h_merchant, h_wnum, h_amount, h_wfee);
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), 'PAY_ADVANCE', :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) 집계 갱신부 - 가맹점 일별 지급 집계 upsert */
    if (pydb_upsert_summary(h_merchant, h_bizdate, h_wnum, h_amount) < 0) {
        setl(b, T_RC, 60);
        Bchg(b, T_MSG, 0, "가맹점 지급집계(py_summary) 갱신 실패", 0L);
        FAIL(b);
    }
    /* 6) 집계/요약 갱신부 - 당일 채널별 지급 생성 누계 재집계 */
    EXEC SQL SELECT count(*), coalesce(sum(net),0) INTO :h_wa1, :h_wa2
        FROM py_payout WHERE merchant_id = :h_merchant
          AND biz_date = :h_bizdate;
    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 merchant_id = :h_merchant AND biz_date = :h_bizdate
          AND status = 'R';
    if (sqlca.sqlcode < 0) h_wa3 = 0;
    if (h_wa1 > 0 && h_wa3 > h_wa1) {
        userlog("%s 요청 잔량 누적: 기준=%ld 실적=%ld", "PAY_ADVANCE", h_wa1, h_wa3);
    }
    /* 8) 응답부 */
    setl(b, T_RC, 0);
    setl(b, T_ID1, h_wlast);
    setl(b, T_FEE, h_wfee);
    setl(b, T_NET, h_wnet);
    Bchg(b, T_MSG, 0, "지급건 생성 완료", 0L);
    userlog("PAY_ADVANCE 완료: last=%ld 건수=%ld 순액=%ld", h_wlast, h_wnum, h_wnet);
    /* 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_ADVANCE", h_wz3, h_wz1);
    }
    if (h_wz2 < 0) {
        setl(b, T_RC, 93);
        Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L);
        FAIL(b);
    }
    OK(b);
}
