/*
 * ACQUIRE.pgc - ac 모듈 서비스 ACQUIRE (one service = one file).
 * 매입 접수(원팁): 가맹점/금액 검증 -> MDR 정책 조회 -> 금액구간·한도 규칙 판정
 * -> purchase/approval 생성 -> RECONCILE 체인 호출 -> 자기 브랜치에서 정산완료(S).
 * 입출력 계약 보존: 입력 T_MERCHANT/T_AMOUNT/T_BIZDATE,
 *                   출력 T_PURCHASE_ID/T_FEE/T_NET/T_STATUS (+ RECONCILE 체인).
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
 */
#include "ACQUIRE.h"

void ACQUIRE(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    const char *SVC = "ACQUIRE";
    char merch[64], bizdate[16], logmsg[256];
    long amount, bps = 25, fee, net, pid, rlen = 0;
    long grade = 0, ratio = 0;
    EXEC SQL BEGIN DECLARE SECTION;
    long h_lim = 0, h_sum = 0, h_cnt = 0, h_openc = 0, h_logid = 0, h_gross = 0;
    long h_amt = 0, h_fee = 0, h_net = 0, h_pid = 0;
    char h_merch[64], h_bizdate[16], h_status[8], h_name[64], h_logmsg[256];
    EXEC SQL END DECLARE SECTION;

    userlog("%s 진입: 신규 매입 접수 요청", SVC);

    /* 1) 입력 검증부: 전 필드 필수/범위/형식 점검 */
    gets_(b, T_MERCHANT, merch, sizeof(merch));
    if (merch[0] == 0) {
        userlog("%s: 가맹점 ID 누락", SVC);
        Bchg(b, T_MSG, 0, "가맹점 ID 누락", 0L); setl(b, T_RC, 101); FAIL(b);
    }
    strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;

    amount = getl(b, T_AMOUNT);
    if (amount <= 0) {
        Bchg(b, T_MSG, 0, "매입 금액 오류", 0L); setl(b, T_RC, 104); FAIL(b);
    }
    if (amount > 100000000L) {
        Bchg(b, T_MSG, 0, "단건 매입 상한 초과", 0L); setl(b, T_RC, 112); FAIL(b);
    }
    h_amt = amount;

    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    if (h_bizdate[0] == 0) {
        EXEC SQL SELECT param_val INTO :h_bizdate FROM cm_param WHERE param_key = 'BIZ_DATE';
        if (sqlca.sqlcode != 0) strcpy(h_bizdate, "2026-07-19");
    }
    if (strlen(h_bizdate) != 10) {
        Bchg(b, T_MSG, 0, "영업일 형식 오류", 0L); setl(b, T_RC, 105); FAIL(b);
    }
    userlog("%s 컨텍스트: merch=%s amount=%ld bizdate=%s", SVC, h_merch, amount, h_bizdate);

    /* 2) 마스터/정책/상태 조회부: 가맹점 마스터 + MDR + 당일 누적 */
    EXEC SQL SELECT name, status, daily_limit INTO :h_name, :h_status, :h_lim
        FROM merchant WHERE merchant_id = :h_merch;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 가맹점마스터 조회 실패 [%d] %s", SVC, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        setl(b, T_RC, 90); FAIL(b);
    }
    if (sqlca.sqlcode == 100) {
        Bchg(b, T_MSG, 0, "가맹점 미존재", 0L); setl(b, T_RC, 110); FAIL(b);
    }
    if (acdb_merchant_mdr(merch, &bps) < 0) bps = 25;   /* keep 25bps default */

    EXEC SQL SELECT count(*), coalesce(sum(amount),0),
                    count(*) FILTER (WHERE status IN ('A','M'))
        INTO :h_cnt, :h_sum, :h_openc FROM purchase
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate
          AND status NOT IN ('C','V');
    if (sqlca.sqlcode < 0) {
        userlog("%s: 당일누적 조회 실패 [%d]", SVC, sqlca.sqlcode);
        setl(b, T_RC, 90); FAIL(b);
    }

    /* 3) 업무규칙 분기부: 가맹점 상태 / 한도 / 금액 구간 (3+ 분기) */
    if (strcmp(h_status, "ACTIVE") != 0) {
        userlog("%s 거절: 가맹점 %s 상태=%s", SVC, h_merch, h_status);
        Bchg(b, T_MSG, 0, "비활성 가맹점", 0L); setl(b, T_RC, 121); FAIL(b);
    }
    if (h_lim > 0 && h_sum + amount > h_lim) {
        userlog("%s 거절: 한도초과 누적=%ld 요청=%ld 한도=%ld", SVC, h_sum, amount, h_lim);
        Bchg(b, T_MSG, 0, "가맹점 일한도 초과", 0L); setl(b, T_RC, 113); FAIL(b);
    }
    if (amount >= 10000000L) {
        grade = 3; Bchg(b, T_MSG, 0, "고액 매입 접수", 0L);
    } else if (amount >= 1000000L) {
        grade = 2; Bchg(b, T_MSG, 0, "중액 매입 접수", 0L);
    } else {
        grade = 1; Bchg(b, T_MSG, 0, "소액 매입 접수", 0L);
    }
    ratio = (h_lim > 0) ? ((h_sum + amount) * 10000L / h_lim) : 0;

    /* 4) 본처리부: 수수료 산출 후 매입/승인 원장 생성 */
    fee = acq_fee(amount, bps);
    net = amount - fee;
    h_fee = fee; h_net = net;

    pid = acdb_next_purchase_id();
    if (pid < 0) { Bchg(b, T_MSG, 0, "매입 채번 실패", 0L); setl(b, T_RC, 93); FAIL(b); }
    if (acdb_insert_purchase(pid, merch, amount, fee, net, "A", "POS", h_bizdate) < 0) {
        Bchg(b, T_MSG, 0, "매입 생성 실패", 0L); setl(b, T_RC, 94); FAIL(b);
    }
    if (acdb_insert_approval(pid, 1) < 0) {
        Bchg(b, T_MSG, 0, "승인 적재 실패", 0L); setl(b, T_RC, 95); FAIL(b);
    }
    h_pid = pid;

    /* 5) 이력/감사 적재부 */
    snprintf(logmsg, sizeof(logmsg), "매입접수 pid=%ld merch=%s 금액=%ld 수수료=%ld 등급=%ld",
             pid, h_merch, amount, fee, grade);
    strncpy(h_logmsg, logmsg, sizeof(h_logmsg)-1); h_logmsg[sizeof(h_logmsg)-1] = 0;
    EXEC SQL SELECT nextval('cm_log_seq') INTO :h_logid;
    if (sqlca.sqlcode < 0) { userlog("%s: 로그채번 실패", SVC); setl(b, T_RC, 90); FAIL(b); }
    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (:h_logid, 'ACQUIRE', 'I', :h_logmsg, :h_bizdate);
    if (sqlca.sqlcode < 0) { userlog("%s: 로그적재 실패", SVC); setl(b, T_RC, 90); FAIL(b); }

    /* 6) 집계/요약 갱신부: 가맹점 일별 요약 재적재 */
    EXEC SQL SELECT count(*), coalesce(sum(amount),0), coalesce(sum(fee),0), coalesce(sum(net),0)
        INTO :h_cnt, :h_gross, :h_fee, :h_net FROM purchase
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { userlog("%s: 요약 재집계 실패", SVC); setl(b, T_RC, 90); FAIL(b); }
    if (acdb_upsert_merch_sum(merch, h_bizdate, h_gross, h_fee, h_net, h_cnt) < 0)
        userlog("%s 주의: 가맹점 요약 갱신 스킵", SVC);

    /* 8) 응답부 (계약 보존: PID/FEE/NET/STATUS) */
    setl(b, T_PURCHASE_ID, pid);
    setl(b, T_FEE, fee);
    setl(b, T_NET, net);
    setl(b, T_ARG1, grade);
    setl(b, T_ARG2, ratio);
    setl(b, T_COUNT, h_cnt);
    Bchg(b, T_STATUS, 0, "A", 0L);

    userlog("ACQUIRE pid=%ld merch=%s amount=%ld fee=%ld net=%ld -> RECONCILE",
            pid, merch, amount, fee, net);

    /* continue the SAME global tx into rc_svr (distinct branch) */
    if (tpcall("RECONCILE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
        userlog("ACQUIRE: tpcall(RECONCILE) FAIL: %s", tpstrerror(tperrno));
        /* 7) 예외/보상부: 체인 실패는 같은 XA 브랜치라 TPFAIL 로 전체 롤백 */
        Bchg(b, T_MSG, 0, "대사 체인 실패", 0L);
        setl(b, T_RC, 114);
        FAIL(b);
    }
    /* our branch resumes: settle-complete the purchase we own */
    if (acdb_update_status(pid, "S") < 0) {
        userlog("%s: 정산완료 전이 실패 pid=%ld", SVC, pid);
        Bchg(b, T_MSG, 0, "정산완료 전이 실패", 0L);
        setl(b, T_RC, 96);
        FAIL(b);
    }
    Bchg(b, T_STATUS, 0, "S", 0L);
    setl(b, T_RC, 0);
    userlog("%s 완료: pid=%ld 상태=S 수수료=%ld 정산=%ld", SVC, pid, fee, net);
    OK(b);
}
