/* @tier hard @module ac @transform acquire-batch */
/*
 * ac_bt_0017.pgc - 매입 이체연계 배치  [tier=hard]
 *
 * 지정 영업일에 정산완료(status='S') 된 매입행을 가맹점별로 집계하여
 * 순지급액(매입금액-수수료 합계) 을 산출하고 이체지시를 생성한다.
 *   - 순지급액이 0원 이하이면 이체 대상에서 제외한다.
 *   - 순지급액이 최소이체금액(AC_BT_0017_MIN_TRANSFER) 미만이면 보류 처리하고
 *     다음 영업일로 넘긴다(이체지시 미생성).
 *   - 그 외에는 이체번호를 채번하여 settle 테이블에 이체지시('T') 로 적재한다.
 * 배치 main 엔트리 포함.
 *
 * 실행:  ac_bt_0017 <YYYYMMDD> [db@host]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "txcore.h"
#include "txcore_dbio.h"
#include "acq_util.h"
#include "ac_core.h"

EXEC SQL INCLUDE sqlca;

#define AC_BT_0017_MIN_TRANSFER 1000L

/*
 * 이체상태 'T' 는 settle 테이블 전용 로컬 상태코드이며,
 * ac_core.h 의 AC_ST_* (ac_ledger 상태) 와는 별개의 값이다.
 */
#define AC_BT_0017_SETTLE_ST_XFER "T"

static int run_ac_bt_0017(const char *biz_date)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_biz_date[9];
    char h_merch_id[16];
    long h_net;
    char h_settle_no[20];
    char h_status[2];
    EXEC SQL END DECLARE SECTION;

    long merchants = 0, transferred = 0, held = 0, skipped = 0, errcnt = 0;
    long seq = 0;
    long grand_net = 0, held_sum = 0;

    strncpy(h_biz_date, biz_date, sizeof(h_biz_date) - 1);
    h_biz_date[sizeof(h_biz_date) - 1] = '\0';

    EXEC SQL DECLARE cur_ac_bt_0017 CURSOR FOR
        SELECT merch_id, sum(amount - fee) AS net
        FROM ac_ledger
        WHERE biz_date = :h_biz_date
          AND status   = 'S'
        GROUP BY merch_id
        ORDER BY merch_id;

    EXEC SQL OPEN cur_ac_bt_0017;
    if (sqlca.sqlcode != TX_SQL_OK) {
        TX_DBIO_LOG_ERR("OPEN cur_ac_bt_0017");
        return TX_EDB;
    }

    if (tx_begin() != TX_OK)
        tx_log(TX_LOG_WARN, "[ac_bt_0017] tx_begin 경고");

    printf("========== 매입 이체연계 결과 [ac_bt_0017] ==========\n");
    printf("  영업일 : %s\n", biz_date);
    printf("  ------------------------------------------------------\n");

    for (;;) {
        EXEC SQL FETCH cur_ac_bt_0017 INTO :h_merch_id, :h_net;

        if (sqlca.sqlcode == TX_SQL_NOTFOUND)
            break;
        if (sqlca.sqlcode != TX_SQL_OK) {
            TX_DBIO_LOG_ERR("FETCH cur_ac_bt_0017");
            errcnt++;
            break;
        }

        merchants++;

        if (h_net <= 0) {
            tx_log(TX_LOG_WARN, "[ac_bt_0017] 순지급액 이하 제외 merch_id=%s net=%ld",
                   h_merch_id, h_net);
            skipped++;
            continue;
        }

        if (h_net < AC_BT_0017_MIN_TRANSFER) {
            tx_log(TX_LOG_INFO, "[ac_bt_0017] 최소이체금액 미만 보류 merch_id=%s net=%ld",
                   h_merch_id, h_net);
            held++;
            held_sum += h_net;
            continue;
        }

        seq++;
        snprintf(h_settle_no, sizeof(h_settle_no), "TR%s%05ld", h_biz_date, seq);
        strncpy(h_status, AC_BT_0017_SETTLE_ST_XFER, sizeof(h_status));

        EXEC SQL INSERT INTO settle
            (settle_no, merch_id, biz_date, settle_amt, status)
            VALUES
            (:h_settle_no, :h_merch_id, :h_biz_date, :h_net, :h_status);

        if (sqlca.sqlcode != TX_SQL_OK) {
            TX_DBIO_LOG_ERR("INSERT ac_bt_0017 settle");
            tx_log(TX_LOG_ERROR, "[ac_bt_0017] 이체지시 생성 실패 merch_id=%s", h_merch_id);
            errcnt++;
            continue;
        }

        printf("  %-16s 이체번호=%-17s 이체금액=%ld\n", h_merch_id, h_settle_no, h_net);

        transferred++;
        grand_net += h_net;
    }

    EXEC SQL CLOSE cur_ac_bt_0017;

    if (errcnt == 0)
        tx_commit();
    else
        tx_abort();

    tx_log(TX_LOG_INFO,
           "[ac_bt_0017] 요약 date=%s 가맹점=%ld 이체=%ld 이체총액=%ld 보류=%ld 보류액=%ld 제외=%ld 오류=%ld",
           biz_date, merchants, transferred, grand_net, held, held_sum, skipped, errcnt);

    printf("  ------------------------------------------------------\n");
    printf("  대상 가맹점수 : %ld\n", merchants);
    printf("  이체 건수     : %ld\n", transferred);
    printf("  이체 총액     : %ld\n", grand_net);
    printf("  보류 건수     : %ld\n", held);
    printf("  보류 금액합   : %ld\n", held_sum);
    printf("  제외 건수     : %ld\n", skipped);
    printf("  오류 건수     : %ld\n", errcnt);
    printf("========================================================\n");

    return (errcnt == 0) ? TX_OK : TX_FAIL;
}

int main(int argc, char **argv)
{
    const char *biz_date;
    const char *target;
    int rc;

    tx_set_loglevel(TX_LOG_INFO);

    if (argc < 2) {
        fprintf(stderr, "사용법: %s <YYYYMMDD> [db@host]\n", argv[0]);
        return 2;
    }
    biz_date = argv[1];
    target   = (argc >= 3) ? argv[2] : NULL;

    if (!date_is_valid(biz_date)) {
        fprintf(stderr, "오류: 유효하지 않은 영업일 '%s'\n", biz_date);
        return 2;
    }

    tx_log(TX_LOG_INFO, "[ac_bt_0017] 배치 시작 date=%s", biz_date);

    rc = ac_dbio_connect(target);
    if (rc != TX_OK) {
        tx_log(TX_LOG_ERROR, "[ac_bt_0017] DB 접속 실패 rc=%d", rc);
        return 1;
    }

    rc = run_ac_bt_0017(biz_date);

    ac_dbio_disconnect();

    tx_log(TX_LOG_INFO, "[ac_bt_0017] 배치 종료 rc=%d(%s)", rc, tx_strerror(rc));
    return (rc == TX_OK) ? 0 : 1;
}
