/*
 * ST_FUNDING.pgc - st (정산/수수료) 모듈 서비스 ST_FUNDING (one service = one file).
 * 가맹점 펀딩 항등식(심화판): 총매출(S) − 환불(C) − 채그백(ac_dispute LOST) − 수수료
 *   (st_fee_component) − 리저브(st_reserve) = 입금(deposit) → st_merchant_funding UPSERT.
 * 처리단계: 입력검증 -> 가맹점 마스터조회 -> 매출/환불/채그백/수수료/리저브 집계
 *   -> 업무규칙(항등식/음수보정) -> st_merchant_funding UPSERT -> 감사이력 -> 재검증 -> 응답 -> 로깅.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). st_svr 가 tpsvrinit 에서 광고.
 * XA 격리: 채그백/수수료/리저브는 본 브랜치에서 조회 가능한 커밋행 기준으로 집계한다.
 */
#include "ST_FUNDING.h"

/* ST_FUNDING - 가맹점 펀딩 항등식(총매출-환불-채그백-수수료-리저브=입금). */
void ST_FUNDING(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ---- 지역 스크래치 (DECLARE SECTION 밖에서 초기화) ---- */
    char  merch[64], bizdate[16], model[16], msgbuf[200];

    EXEC SQL BEGIN DECLARE SECTION;
    long  h_mcnt, h_gross, h_refunds, h_cb, h_fees, h_reserve, h_deposit;
    long  h_scnt, h_ccnt, h_mdr, h_limit, h_chk;
    char  h_merch[64], h_bizdate[16], h_model[16], h_mstatus[16], h_svc[24], h_msg[200];
    EXEC SQL END DECLARE SECTION;

    strcpy(h_svc, "ST_FUNDING");
    h_mcnt = h_gross = h_refunds = h_cb = h_fees = h_reserve = h_deposit = 0;
    h_scnt = h_ccnt = h_chk = 0; h_mdr = 25; h_limit = 0;
    strcpy(h_mstatus, "ACTIVE"); strcpy(h_model, "NET_DAILY");

    /* ===== 1) 입력 검증부 ===== */
    gets_(b, T_MERCHANT, merch, sizeof(merch));
    gets_(b, T_BIZDATE,  bizdate, sizeof(bizdate));
    gets_(b, T_STR1,     model,   sizeof(model));   /* 선택: 펀딩모델 */
    if (model[0] == 0) strcpy(model, "NET_DAILY");
    userlog("[정산심화] 가맹점 펀딩 항등식 진입 merch=%s biz=%s model=%s", merch, bizdate, model);
    if (merch[0] == 0) {
        setl(b, T_RC, 8301); Bchg(b, T_MSG, 0, "가맹점 ID(merchant_id) 필수", 0L);
        userlog("[ST_FUNDING] 가맹점 ID 누락"); FAIL(b);
    }
    if (strlen(bizdate) < 8) {
        setl(b, T_RC, 8302); Bchg(b, T_MSG, 0, "영업일자(biz_date) 형식 오류", 0L);
        userlog("[ST_FUNDING] 영업일 검증 실패 val=[%s]", bizdate); FAIL(b);
    }
    strncpy(h_merch, merch, sizeof(h_merch)-1);   h_merch[sizeof(h_merch)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    strncpy(h_model, model, sizeof(h_model)-1);   h_model[sizeof(h_model)-1] = 0;

    /* ===== 2) 가맹점 마스터 조회부 ===== */
    EXEC SQL SELECT mdr_bps, daily_limit, status
        INTO :h_mdr, :h_limit, :h_mstatus FROM merchant WHERE merchant_id = :h_merch;
    if (sqlca.sqlcode == 100) {
        strcpy(h_mstatus, "NOMERCH"); h_mdr = 25; h_limit = 0;
        userlog("[ST_FUNDING] 가맹점 마스터 미존재 mid=[%s] 기본정책 적용", h_merch);
    } else if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8310); Bchg(b, T_MSG, 0, "가맹점 마스터 조회 오류", 0L); FAIL(b);
    }

    /* ===== 3) 매출/환불/채그백/수수료/리저브 집계부 ===== */
    /* 총매출(S) + 환불(C) — 상태별 분기 집계 */
    EXEC SQL SELECT
        coalesce(sum(CASE WHEN status = 'S' THEN amount ELSE 0 END),0),
        coalesce(sum(CASE WHEN status = 'C' THEN amount ELSE 0 END),0),
        coalesce(sum(CASE WHEN status = 'S' THEN 1 ELSE 0 END),0),
        coalesce(sum(CASE WHEN status = 'C' THEN 1 ELSE 0 END),0),
        count(*)
        INTO :h_gross, :h_refunds, :h_scnt, :h_ccnt, :h_mcnt
        FROM purchase WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8320); Bchg(b, T_MSG, 0, "매출/환불 집계 오류", 0L); FAIL(b); }
    /* 수수료(MDR 합계) = st_fee_component.mdr_total */
    EXEC SQL SELECT coalesce(sum(fc.mdr_total),0) INTO :h_fees
        FROM st_fee_component fc JOIN purchase p ON p.purchase_id = fc.purchase_id
        WHERE p.merchant_id = :h_merch AND p.biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8321); Bchg(b, T_MSG, 0, "수수료 집계 오류", 0L); FAIL(b); }
    /* 채그백 = 확정손실(ac_dispute LOST) 금액 */
    EXEC SQL SELECT coalesce(sum(d.amount),0) INTO :h_cb
        FROM ac_dispute d JOIN purchase p ON p.purchase_id = d.purchase_id
        WHERE p.merchant_id = :h_merch AND p.biz_date = :h_bizdate AND d.status = 'LOST';
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8322); Bchg(b, T_MSG, 0, "채그백 집계 오류", 0L); FAIL(b); }
    /* 리저브 = 당일 유보액(없으면 0) */
    EXEC SQL SELECT reserve_amt INTO :h_reserve FROM st_reserve
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode == 100) { h_reserve = 0;
        userlog("[ST_FUNDING] 리저브 미설정 mid=%s biz=%s — 0 처리", h_merch, h_bizdate); }
    else if (sqlca.sqlcode < 0) { setl(b, T_RC, 8323); Bchg(b, T_MSG, 0, "리저브 조회 오류", 0L); FAIL(b); }
    userlog("[ST_FUNDING] 집계 gross=%ld refunds=%ld cb=%ld fees=%ld reserve=%ld (S=%ld C=%ld)",
            h_gross, h_refunds, h_cb, h_fees, h_reserve, h_scnt, h_ccnt);

    /* ===== 4) 업무규칙 분기부 (항등식/음수보정) ===== */
    if (h_gross <= 0) {
        Bchg(b, T_STATUS, 0, "NODATA", 0L);
        setl(b, T_AMT1, 0); setl(b, T_AMT2, 0); setl(b, T_AMT3, 0);
        Bchg(b, T_SVCNAME, 0, "ST_FUNDING", 0L); setl(b, T_RC, 0);
        userlog("[ST_FUNDING] 당일 매출 없음 merch=%s biz=%s — 무처리 종료", h_merch, h_bizdate);
        OK(b);
    }
    h_deposit = h_gross - h_refunds - h_cb - h_fees - h_reserve;   /* 펀딩 항등식 */
    if (h_deposit < 0)
        userlog("[ST_FUNDING] 입금액 음수(차감 초과) merch=%s deposit=%ld — 익일 이월 대상", h_merch, h_deposit);

    /* ===== 5) 본처리부 (st_merchant_funding UPSERT) ===== */
    EXEC SQL INSERT INTO st_merchant_funding
        (funding_id, merchant_id, biz_date, gross_sales, refunds, chargebacks,
         fees, reserve, deposit, funding_model, status)
        VALUES (nextval('st_funding_seq'), :h_merch, :h_bizdate, :h_gross, :h_refunds, :h_cb,
                :h_fees, :h_reserve, :h_deposit, :h_model, 'FUNDED')
        ON CONFLICT (merchant_id, biz_date) DO UPDATE SET
            gross_sales = excluded.gross_sales, refunds = excluded.refunds,
            chargebacks = excluded.chargebacks, fees = excluded.fees,
            reserve = excluded.reserve, deposit = excluded.deposit,
            funding_model = excluded.funding_model, status = 'FUNDED', funded_at = now();
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8330); Bchg(b, T_MSG, 0, "펀딩 UPSERT 실패", 0L);
        userlog("[ST_FUNDING] st_merchant_funding UPSERT 실패 [%d]", sqlca.sqlcode); FAIL(b);
    }

    /* ===== 6) 감사이력 적재부 (cm_log) ===== */
    snprintf(msgbuf, sizeof(msgbuf), "ST_FUNDING merch=%s biz=%s gross=%ld fees=%ld cb=%ld deposit=%ld",
             h_merch, h_bizdate, h_gross, h_fees, h_cb, h_deposit);
    strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0;
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8340); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); }

    /* ===== 7) 재검증부 (항등식 검산 — 적재행 재조회) ===== */
    EXEC SQL SELECT deposit INTO :h_chk FROM st_merchant_funding
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
        setl(b, T_RC, 8350); Bchg(b, T_MSG, 0, "펀딩 적재 재검증 실패", 0L);
        userlog("[ST_FUNDING] 재검증 실패 code=%d", sqlca.sqlcode); FAIL(b);
    }
    if (h_chk != h_deposit) {
        setl(b, T_RC, 8351); Bchg(b, T_MSG, 0, "펀딩 항등식 불일치(보상 롤백)", 0L);
        userlog("[ST_FUNDING] 항등식 불일치 chk=%ld deposit=%ld", h_chk, h_deposit); FAIL(b);
    }

    /* ===== 8) 응답부 (출력 필드 설정) ===== */
    setl(b, T_AMT1, h_gross);     /* gross   */
    setl(b, T_AMT2, h_fees);      /* fees    */
    setl(b, T_AMT3, h_deposit);   /* deposit */
    setl(b, T_AMT4, h_reserve);   /* reserve(참고) */
    setl(b, T_GROSS, h_gross);
    setl(b, T_FEE, h_fees);
    setl(b, T_NET, h_deposit);
    setl(b, T_COUNT, h_mcnt);
    Bchg(b, T_STATUS, 0, "FUNDED", 0L);
    Bchg(b, T_SVCNAME, 0, "ST_FUNDING", 0L);
    setl(b, T_RC, 0);

    /* ===== 9) 완료 로깅 ===== */
    userlog("[정산심화] 가맹점 펀딩 완료 merch=%s biz=%s gross=%ld fees=%ld deposit=%ld",
            h_merch, h_bizdate, h_gross, h_fees, h_deposit);
    OK(b);
}

/* vim: set ts=4 sw=4 et smartindent: */
