/*
 * ST_FUNDINSTR.pgc - st (정산/수수료) 모듈 서비스 ST_FUNDINSTR (one service = one file).
 * 펀딩 지시 생성/확인: 가맹점 순액정산 결과(st_merchant_funding.deposit)를 은행
 *   rails(FIRMBANK) 지급지시로 전환해 st_funding_instr 에 적재한다. 이미 당일
 *   지시가 있으면 재생성 없이 "확인"으로 그 지시를 반환한다(멱등). deposit<=0 이면
 *   지급 불가로 RETURNED(반환) 지시를 남긴다.
 * 처리단계: 입력검증 -> 펀딩(deposit) 조회 -> 기지시 확인 -> 업무규칙(반환/지급) ->
 *   본처리(st_funding_instr INSERT) -> 감사이력 -> 재검증 -> 응답 -> 로깅.
 * 호출자 XA 브랜치에서 수행(EXEC SQL CONNECT 없음). st_svr 가 tpsvrinit 에서 광고.
 * XA 격리: 펀딩/기지시는 본 브랜치에서 조회 가능한 커밋행 기준으로 판정한다.
 */
#include "ST_FUNDINSTR.h"

/* ST_FUNDINSTR - 펀딩 지시 생성/확인(은행 rails 지급지시). */
void ST_FUNDINSTR(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ---- 지역 스크래치 (DECLARE SECTION 밖에서 초기화) ---- */
    char  merch[64], bizdate[16], msgbuf[220];
    unsigned long hv;
    int   i, banksel;
    static const char *BANKS[5] = { "KB", "SHINHAN", "HANA", "NH", "WOORI" };

    EXEC SQL BEGIN DECLARE SECTION;
    long  h_deposit, h_amount, h_instr, h_exist, h_chk;
    char  h_merch[64], h_bizdate[16], h_bank[16], h_acct[24], h_rail[16];
    char  h_status[16], h_rcode[32], h_estatus[16], h_svc[24], h_msg[220];
    EXEC SQL END DECLARE SECTION;

    strcpy(h_svc, "ST_FUNDINSTR");
    h_deposit = h_amount = h_instr = h_exist = h_chk = 0;
    strcpy(h_rail, "FIRMBANK"); strcpy(h_status, "SENT");
    strcpy(h_bank, "KB"); h_acct[0] = 0; h_rcode[0] = 0; h_estatus[0] = 0;

    /* ===== 1) 입력 검증부 ===== */
    gets_(b, T_MERCHANT, merch, sizeof(merch));
    gets_(b, T_BIZDATE,  bizdate, sizeof(bizdate));
    userlog("[자금연동] 펀딩 지시 진입 merch=%s biz=%s", merch, bizdate);
    if (merch[0] == 0) {
        setl(b, T_RC, 8601); Bchg(b, T_MSG, 0, "가맹점 ID(merchant_id) 필수", 0L);
        userlog("[ST_FUNDINSTR] 가맹점 ID 누락"); FAIL(b);
    }
    if (strlen(bizdate) < 8) {
        setl(b, T_RC, 8602); Bchg(b, T_MSG, 0, "영업일자(biz_date) 형식 오류", 0L);
        userlog("[ST_FUNDINSTR] 영업일 검증 실패 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;

    /* 은행/계좌 결정: 가맹점 ID 해시로 결정(마스터 없는 데모 지급계좌). */
    hv = 5381UL;
    for (i = 0; h_merch[i] != 0; i++) hv = ((hv << 5) + hv) + (unsigned char)h_merch[i];
    banksel = (int)(hv % 5);
    strncpy(h_bank, BANKS[banksel], sizeof(h_bank)-1); h_bank[sizeof(h_bank)-1] = 0;
    snprintf(h_acct, sizeof(h_acct), "%012lu", (hv >> 3) % 1000000000000UL);

    /* ===== 2) 펀딩(deposit) 조회부 ===== */
    EXEC SQL SELECT deposit INTO :h_deposit FROM st_merchant_funding
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode == 100) {
        /* 당일 펀딩 산출이 없으면 지시 대상 아님(무처리 종료 — ST_FUNDING NODATA 규율). */
        Bchg(b, T_STATUS, 0, "NOFUND", 0L);
        setl(b, T_AMT1, 0); setl(b, T_ID1, 0);
        Bchg(b, T_SVCNAME, 0, "ST_FUNDINSTR", 0L); setl(b, T_RC, 0);
        userlog("[ST_FUNDINSTR] 펀딩 미산출 merch=%s biz=%s — 지시 대상 없음", h_merch, h_bizdate);
        OK(b);
    } else if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8610); Bchg(b, T_MSG, 0, "펀딩 조회 오류", 0L);
        userlog("[ST_FUNDINSTR] 펀딩 조회 실패 [%d]", sqlca.sqlcode); FAIL(b);
    }
    h_amount = h_deposit;

    /* ===== 3) 기지시 확인부 (멱등: 이미 있으면 그 지시를 반환) ===== */
    EXEC SQL SELECT instr_id, amount, status INTO :h_exist, :h_amount, :h_estatus
        FROM st_funding_instr WHERE merchant_id = :h_merch AND biz_date = :h_bizdate
        ORDER BY instr_id LIMIT 1;
    if (sqlca.sqlcode == 0) {
        setl(b, T_AMT1, h_amount);
        Bchg(b, T_STATUS, 0, h_estatus, 0L);
        setl(b, T_ID1, h_exist);
        Bchg(b, T_SVCNAME, 0, "ST_FUNDINSTR", 0L); setl(b, T_RC, 0);
        userlog("[ST_FUNDINSTR] 기지시 확인 instr=%ld amount=%ld status=%s", h_exist, h_amount, h_estatus);
        OK(b);
    } else if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8611); Bchg(b, T_MSG, 0, "기지시 조회 오류", 0L); FAIL(b);
    }
    h_amount = h_deposit;

    /* ===== 4) 업무규칙 분기부 (지급/반환) ===== */
    if (h_deposit <= 0) {
        strcpy(h_status, "RETURNED");
        strcpy(h_rcode, "R02-지급액없음");
        userlog("[ST_FUNDINSTR] 입금액 비양수 deposit=%ld — 반환 지시 생성", h_deposit);
    } else {
        strcpy(h_status, "SENT"); h_rcode[0] = 0;
    }

    /* ===== 5) 본처리부 (st_funding_instr INSERT) ===== */
    EXEC SQL SELECT nextval('st_fundinstr_seq') INTO :h_instr;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 8620); Bchg(b, T_MSG, 0, "지시 시퀀스 실패", 0L); FAIL(b); }
    if (h_rcode[0] == 0) {
        EXEC SQL INSERT INTO st_funding_instr
            (instr_id, merchant_id, biz_date, bank_code, account_no, amount, rail, status)
            VALUES (:h_instr, :h_merch, :h_bizdate, :h_bank, :h_acct, :h_amount, :h_rail, :h_status);
    } else {
        EXEC SQL INSERT INTO st_funding_instr
            (instr_id, merchant_id, biz_date, bank_code, account_no, amount, rail, status, return_code)
            VALUES (:h_instr, :h_merch, :h_bizdate, :h_bank, :h_acct, :h_amount, :h_rail, :h_status, :h_rcode);
    }
    if (sqlca.sqlcode < 0) {
        setl(b, T_RC, 8621); Bchg(b, T_MSG, 0, "펀딩 지시 적재 실패", 0L);
        userlog("[ST_FUNDINSTR] st_funding_instr INSERT 실패 [%d]", sqlca.sqlcode); FAIL(b);
    }

    /* ===== 6) 감사이력 적재부 (cm_log) ===== */
    snprintf(msgbuf, sizeof(msgbuf), "ST_FUNDINSTR merch=%s biz=%s bank=%s acct=%s amount=%ld status=%s",
             h_merch, h_bizdate, h_bank, h_acct, h_amount, h_status);
    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, 8630); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); }

    /* ===== 7) 재검증부 (적재행 재조회) ===== */
    EXEC SQL SELECT amount INTO :h_chk FROM st_funding_instr WHERE instr_id = :h_instr;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
        setl(b, T_RC, 8640); Bchg(b, T_MSG, 0, "지시 적재 재검증 실패", 0L);
        userlog("[ST_FUNDINSTR] 재검증 실패 code=%d", sqlca.sqlcode); FAIL(b);
    }
    if (h_chk != h_amount) {
        setl(b, T_RC, 8641); Bchg(b, T_MSG, 0, "지시 금액 불일치(보상 롤백)", 0L);
        userlog("[ST_FUNDINSTR] 금액 불일치 chk=%ld amount=%ld", h_chk, h_amount); FAIL(b);
    }

    /* ===== 8) 응답부 (계약: T_AMT1=amount, T_STATUS=status, T_ID1=instr_id) ===== */
    setl(b, T_AMT1, h_amount);
    setl(b, T_AMT2, h_deposit);
    Bchg(b, T_STATUS, 0, h_status, 0L);
    setl(b, T_ID1, h_instr);
    Bchg(b, T_MERCHANT, 0, h_merch, 0L);
    Bchg(b, T_STR1, 0, h_bank, 0L);
    Bchg(b, T_STR2, 0, h_acct, 0L);
    Bchg(b, T_SVCNAME, 0, "ST_FUNDINSTR", 0L);
    setl(b, T_RC, 0);

    /* ===== 9) 완료 로깅 ===== */
    userlog("[자금연동] 펀딩 지시 완료 merch=%s biz=%s instr=%ld amount=%ld status=%s",
            h_merch, h_bizdate, h_instr, h_amount, h_status);
    OK(b);
}

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