/*
 * ACQ_MERCHSUM.pgc - ac 모듈 서비스 ACQ_MERCHSUM (one service = one file).
 * 가맹점 일별 집계: 영업일 매입을 재집계해 merchant_summary 에 upsert 하고
 * 건수/총액을 회신한다. 상태별 분해와 직전일 대비 추세도 함께 산출한다.
 * 입출력 계약 보존: 입력 T_MERCHANT/T_BIZDATE, 출력 T_COUNT/T_GROSS
 *                   (acdb_upsert_merch_sum 반영).
 * Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
 */
#include "ACQ_MERCHSUM.h"

void ACQ_MERCHSUM(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    const char *SVC = "ACQ_MERCHSUM";
    char merch[64], bizdate[16], logmsg[256];
    long trend = 0, ratio = 0;
    EXEC SQL BEGIN DECLARE SECTION;
    long h_cnt, h_gross, h_fee, h_net;
    long h_a = 0, h_m = 0, h_s = 0, h_c = 0, h_pd = 0, h_lim = 0, h_logid = 0;
    char h_merch[64], h_bizdate[16], h_status[8], h_logmsg[256];
    EXEC SQL END DECLARE SECTION;

    userlog("%s 진입: 가맹점 일별 집계 요청", SVC);

    /* 1) 입력 검증부 */
    gets_(b, T_MERCHANT, merch, sizeof(merch));
    if (merch[0] == 0) {
        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;

    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);
    }
    strncpy(bizdate, h_bizdate, sizeof(bizdate)-1); bizdate[sizeof(bizdate)-1] = 0;
    userlog("%s 컨텍스트: merch=%s bizdate=%s", SVC, h_merch, h_bizdate);

    /* 2) 마스터 조회부: 가맹점 존재/상태 확인 */
    EXEC SQL SELECT status, daily_limit INTO :h_status, :h_lim
        FROM merchant WHERE merchant_id = :h_merch;
    if (sqlca.sqlcode < 0) {
        userlog("%s: 가맹점 조회 실패 [%d]", SVC, sqlca.sqlcode); 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 (strcmp(h_status, "ACTIVE") != 0)
        userlog("%s 주의: 가맹점 %s 상태=%s", SVC, h_merch, h_status);

    /* 4) 본처리부: 영업일 실적 재집계 (계약 보존 질의) */
    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: 실적 집계 실패 [%d]", SVC, sqlca.sqlcode); setl(b, T_RC, 90); FAIL(b);
    }

    /* 상태별 분해 및 직전일 실적 */
    EXEC SQL SELECT count(*) FILTER (WHERE status = 'A'), count(*) FILTER (WHERE status = 'M'),
                    count(*) FILTER (WHERE status = 'S'), count(*) FILTER (WHERE status = 'C')
        INTO :h_a, :h_m, :h_s, :h_c FROM purchase
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 90); FAIL(b); }

    EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_pd FROM purchase
        WHERE merchant_id = :h_merch AND biz_date = (:h_bizdate::date - 1);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 90); FAIL(b); }

    /* 3) 업무규칙 분기부: 실적 규모/추세/한도 소진 판정 (3+ 분기) */
    trend = (h_pd > 0) ? (h_gross * 100L / h_pd) : 0;
    ratio = (h_lim > 0) ? (h_gross * 10000L / h_lim) : 0;
    if (h_cnt == 0) {
        Bchg(b, T_MSG, 0, "당일 실적 없음", 0L);
    } else if (ratio >= 9000) {
        Bchg(b, T_MSG, 0, "한도 임박 실적", 0L);
    } else if (trend >= 200) {
        Bchg(b, T_MSG, 0, "직전일 대비 급증", 0L);
    } else if (trend > 0 && trend <= 50) {
        Bchg(b, T_MSG, 0, "직전일 대비 급감", 0L);
    } else {
        Bchg(b, T_MSG, 0, "정상 실적", 0L);
    }

    /* 6) 집계/요약 갱신부 (계약 보존: upsert 수행) */
    if (acdb_upsert_merch_sum(merch, bizdate, h_gross, h_fee, h_net, h_cnt) < 0) {
        userlog("%s: 요약 upsert 실패 merch=%s", SVC, h_merch);
        Bchg(b, T_MSG, 0, "요약 갱신 실패", 0L); setl(b, T_RC, 92); FAIL(b);
    }

    /* 5) 이력/감사 적재부 */
    snprintf(logmsg, sizeof(logmsg), "가맹점집계 merch=%s 건수=%ld 총액=%ld 수수료=%ld 추세=%ld",
             h_merch, h_cnt, h_gross, h_fee, trend);
    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) { 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, 'ACQ_MERCHSUM', 'I', :h_logmsg, :h_bizdate);
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 90); FAIL(b); }

    /* --- 업무 체인: 가맹점 실적 요약 -> 가맹점 마스터 조회(MM_MERCH_INQ) ---
     * 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
     * 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
     * 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
     * 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
    {
        long rlen = 0, chain_rc = 0;
        char keep_status[16];

        keep_status[0] = 0;
        gets_(b, T_STATUS, keep_status, sizeof(keep_status));
        Bchg(b, T_SVCNAME, 0, "ACQ_MERCHSUM", 0L);
        Bchg(b, T_MERCHANT, 0, h_merch, 0L);
        Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);

        /* 1단계: 요약에 붙일 가맹점 등급/상태를 마스터계에서 받아온다 */
        setl(b, T_COUNT, h_cnt);
        setl(b, T_AMT1, h_gross);
        if (tpcall("MM_MERCH_INQ", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
            userlog("%s: tpcall(MM_MERCH_INQ) 실패: %s", SVC, tpstrerror(tperrno));
            Bchg(b, T_MSG, 0, "가맹점 마스터 조회 실패", 0L); setl(b, T_RC, 621);
            FAIL(b);
        }
        chain_rc = getl(b, T_RC);
        userlog("%s 체인: MM_MERCH_INQ 응답 rc=%ld", SVC, chain_rc);

        /* 하위가 덮어쓴 자기 상태 계약값 복원 */
        if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
        setl(b, T_RC, 0);
    }

    /* 8) 응답부 (계약 보존: T_COUNT / T_GROSS) */
    setl(b, T_COUNT, h_cnt);
    setl(b, T_GROSS, h_gross);
    setl(b, T_FEE, h_fee);
    setl(b, T_NET, h_net);
    setl(b, T_ARG1, h_a);
    setl(b, T_ARG2, h_m);
    setl(b, T_ARG3, h_s);
    setl(b, T_ARG4, h_c);
    setl(b, T_ARG5, trend);
    setl(b, T_ARG6, ratio);
    setl(b, T_RC, 0);
    userlog("%s 완료: merch=%s 건수=%ld 총액=%ld", SVC, h_merch, h_cnt, h_gross);
    OK(b);
}
