/*
 * ST_NETSETTLE.pgc - st (정산/수수료) 모듈 서비스 ST_NETSETTLE (one service = one file).
 * 발급사(회원 BIN)별 순액정산 배치(심화판). 해당 영업일의 st_fee_component+purchase 를
 *   회원사(st_member_bank) BIN 별로 집계 → gross/interchange/scheme 합산, net=gross-ic-sf
 *   → st_net_settlement UPSERT(ON CONFLICT scheme,member_bin,biz_date).
 * 처리단계: 입력검증 -> 참가회원사/대상건 조회 -> 업무규칙(대상유무) -> 순액배치 UPSERT(집합기반)
 *   -> 결과 커서순회 로깅 -> 감사이력 -> 총계 재집계 -> 응답 -> 로깅.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). st_svr 가 tpsvrinit 에서 광고.
 * 쓰기 소유자 단일화(owner-writes): 순액배치 UPSERT 는 집합기반 단일 문장으로 수행한다.
 */
#include "ST_NETSETTLE.h"

/* ST_NETSETTLE - 발급사별 순액정산 배치. */
void ST_NETSETTLE(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ---- 지역 스크래치 (DECLARE SECTION 밖에서 초기화) ---- */
    char  bizdate[16], issuer[40], msgbuf[200];
    long  rows = 0;

    EXEC SQL BEGIN DECLARE SECTION;
    long  h_members, h_srccnt, h_upcnt, h_tcnt, h_tgross, h_tic, h_tsf, h_tnet;
    long  h_rcnt, h_rgross, h_rnet;
    char  h_bizdate[16], h_issuer[40], h_bin[16], h_dir[16], h_svc[24], h_msg[200];
    EXEC SQL END DECLARE SECTION;

    strcpy(h_svc, "ST_NETSETTLE");
    h_members = h_srccnt = h_upcnt = 0;
    h_tcnt = h_tgross = h_tic = h_tsf = h_tnet = 0;
    h_rcnt = h_rgross = h_rnet = 0;
    strcpy(h_bin, "-"); strcpy(h_dir, "RECEIVE");

    /* ===== 1) 입력 검증부 ===== */
    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    gets_(b, T_ISSUER,  issuer,  sizeof(issuer));   /* 선택: 특정 발급사만 */
    if (strlen(bizdate) < 8) {
        setl(b, T_RC, 8201); Bchg(b, T_MSG, 0, "영업일자(biz_date) 형식 오류", 0L);
        userlog("[ST_NETSETTLE] 영업일 검증 실패 val=[%s]", bizdate); FAIL(b);
    }
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    strncpy(h_issuer, issuer, sizeof(h_issuer)-1);   h_issuer[sizeof(h_issuer)-1] = 0;
    userlog("[정산심화] 발급사별 순액정산 배치 진입 biz=%s issuer=[%s]", h_bizdate, h_issuer);

    /* ===== 2) 참가 회원사/대상건 조회부 ===== */
    EXEC SQL SELECT count(*) INTO :h_members FROM st_member_bank
        WHERE role IN ('ISSUER', 'BOTH') AND (:h_issuer = '' OR bank_code = :h_issuer);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8210); Bchg(b, T_MSG, 0, "회원사 조회 오류", 0L); FAIL(b); }
    EXEC SQL SELECT count(*) INTO :h_srccnt
        FROM st_fee_component fc JOIN purchase p ON p.purchase_id = fc.purchase_id
        JOIN st_member_bank mb ON mb.bank_code = p.issuer
        WHERE p.biz_date = :h_bizdate AND (:h_issuer = '' OR p.issuer = :h_issuer);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8211); Bchg(b, T_MSG, 0, "정산 대상 조회 오류", 0L); FAIL(b); }
    userlog("[ST_NETSETTLE] 참가 회원사=%ld 대상 분해건=%ld", h_members, h_srccnt);

    /* ===== 3) 업무규칙 분기부 (대상 유무) ===== */
    if (h_srccnt <= 0) {
        Bchg(b, T_STATUS, 0, "NODATA", 0L);
        setl(b, T_ARG1, 0); setl(b, T_AMT1, 0); setl(b, T_AMT2, 0);
        Bchg(b, T_SVCNAME, 0, "ST_NETSETTLE", 0L); setl(b, T_RC, 0);
        userlog("[ST_NETSETTLE] 대상 없음 biz=%s — 무처리 종료", h_bizdate);
        OK(b);
    }

    /* ===== 4) 본처리부: 발급사 BIN×영업일 순액배치 UPSERT (집합기반 단일문장) =====
     * net_amt = gross - interchange - scheme_fee (부호=수취/지급 방향). */
    EXEC SQL INSERT INTO st_net_settlement
        (net_id, scheme, member_bin, biz_date, txn_count,
         gross_amt, interchange_amt, scheme_fee_amt, net_amt, direction, status)
        SELECT nextval('st_netset_seq'), 'BC', mb.bin, p.biz_date, count(*),
               coalesce(sum(fc.amount),0), coalesce(sum(fc.interchange),0), coalesce(sum(fc.scheme_fee),0),
               coalesce(sum(fc.amount - fc.interchange - fc.scheme_fee),0),
               CASE WHEN coalesce(sum(fc.amount - fc.interchange - fc.scheme_fee),0) >= 0
                    THEN 'RECEIVE' ELSE 'PAY' END,
               'SETTLED'
        FROM st_fee_component fc
        JOIN purchase p ON p.purchase_id = fc.purchase_id
        JOIN st_member_bank mb ON mb.bank_code = p.issuer
        WHERE p.biz_date = :h_bizdate AND (:h_issuer = '' OR p.issuer = :h_issuer)
        GROUP BY mb.bin, p.biz_date
        ON CONFLICT (scheme, member_bin, biz_date) DO UPDATE SET
            txn_count = excluded.txn_count, gross_amt = excluded.gross_amt,
            interchange_amt = excluded.interchange_amt, scheme_fee_amt = excluded.scheme_fee_amt,
            net_amt = excluded.net_amt, direction = excluded.direction, settled_at = now();
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8220); Bchg(b, T_MSG, 0, "순액정산 배치 UPSERT 실패", 0L);
        userlog("[ST_NETSETTLE] st_net_settlement UPSERT 실패 [%d]", sqlca.sqlcode); FAIL(b);
    }
    h_upcnt = sqlca.sqlerrd[2];   /* 처리 행수 */
    userlog("[ST_NETSETTLE] 순액배치 UPSERT 처리행=%ld", h_upcnt);

    /* ===== 5) 결과 커서 순회 로깅부 (같은 XA 브랜치 — 방금 UPSERT 가시) ===== */
    EXEC SQL DECLARE cur_netset CURSOR FOR
        SELECT member_bin, txn_count, gross_amt, net_amt, direction
          FROM st_net_settlement
         WHERE biz_date = :h_bizdate
           AND (:h_issuer = '' OR member_bin IN (SELECT bin FROM st_member_bank WHERE bank_code = :h_issuer))
         ORDER BY member_bin;
    EXEC SQL OPEN cur_netset;
    for (;;) {
        EXEC SQL FETCH cur_netset INTO :h_bin, :h_rcnt, :h_rgross, :h_rnet, :h_dir;
        if (sqlca.sqlcode == 100) break;
        if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_netset; setl(b, T_RC, 8230);
            Bchg(b, T_MSG, 0, "순액정산 결과 순회 오류", 0L); FAIL(b); }
        rows++;
        userlog("[ST_NETSETTLE] BIN=%s cnt=%ld gross=%ld net=%ld dir=%s",
                h_bin, h_rcnt, h_rgross, h_rnet, h_dir);
    }
    EXEC SQL CLOSE cur_netset;

    /* ===== 6) 감사이력 적재부 (cm_log) ===== */
    snprintf(msgbuf, sizeof(msgbuf), "ST_NETSETTLE biz=%s members=%ld src=%ld upsert=%ld rows=%ld",
             h_bizdate, h_members, h_srccnt, h_upcnt, rows);
    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, 8240); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); }

    /* ===== 7) 총계 재집계부 ===== */
    EXEC SQL SELECT coalesce(sum(txn_count),0), coalesce(sum(gross_amt),0),
                    coalesce(sum(interchange_amt),0), coalesce(sum(scheme_fee_amt),0),
                    coalesce(sum(net_amt),0)
        INTO :h_tcnt, :h_tgross, :h_tic, :h_tsf, :h_tnet
        FROM st_net_settlement
        WHERE biz_date = :h_bizdate
          AND (:h_issuer = '' OR member_bin IN (SELECT bin FROM st_member_bank WHERE bank_code = :h_issuer));
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8250); Bchg(b, T_MSG, 0, "순액정산 총계 재집계 오류", 0L); FAIL(b); }

    /* ===== 8) 응답부 (출력 필드 설정) ===== */
    setl(b, T_ARG1, h_tcnt);      /* txn_count 총계 */
    setl(b, T_AMT1, h_tgross);    /* gross 총계     */
    setl(b, T_AMT2, h_tnet);      /* net 총계       */
    setl(b, T_AMT3, h_tic);       /* interchange 총계(참고) */
    setl(b, T_COUNT, rows);       /* 정산 BIN 수    */
    Bchg(b, T_STATUS, 0, "SETTLED", 0L);
    Bchg(b, T_SVCNAME, 0, "ST_NETSETTLE", 0L);
    setl(b, T_RC, 0);

    /* ===== 9) 완료 로깅 ===== */
    userlog("[정산심화] 발급사별 순액정산 완료 biz=%s bins=%ld txn=%ld gross=%ld net=%ld",
            h_bizdate, rows, h_tcnt, h_tgross, h_tnet);
    OK(b);
}

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