/*
 * lg_monthclose_batch.pgc - lg 월차 결산 분개 배치 (커서 + XA).
 *
 * 월 구간 [FROM ~ TO] 의 손익계정(FEE_INC/BADDEBT_EXP/FEE_DEPT_%)을 커서로
 * 돌며 각 순액을 RETAINED 로 대체하는 결산 전표 라인을 만든다. 전 계정을
 * 하나의 결산 전표에 담되 상대 라인은 RETAINED 한 줄로 몰아 차변합=대변합을
 * 보장한다 (복식부기 균형). 모두 ONE global XA transaction 에서 수행.
 * Usage: lg_monthclose_batch [FROM] [TO]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "lg_dbio.h"
#include "lg_monthclose_batch.h"

int main(int argc, char **argv)
{
    lg_monthclose_rec_t rec;
    long vid, retained = 0, mag;

    EXEC SQL BEGIN DECLARE SECTION;
    char h_from[16], h_to[16], h_acct[32];
    long h_net;
    EXEC SQL END DECLARE SECTION;

    memset(&rec, 0, sizeof(rec));
    strncpy(rec.month_from, (argc > 1) ? argv[1] : "2026-07-01", sizeof(rec.month_from)-1);
    strncpy(rec.month_to,   (argc > 2) ? argv[2] : "2026-07-31", sizeof(rec.month_to)-1);
    strncpy(h_from, rec.month_from, sizeof(h_from)-1); h_from[sizeof(h_from)-1] = 0;
    strncpy(h_to, rec.month_to, sizeof(h_to)-1); h_to[sizeof(h_to)-1] = 0;

    if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
    if (tpopen() < 0)     { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
    if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }

    vid = lgdb_next_voucher_id();
    if (vid < 0) { tpabort(0); return 1; }
    if (lgdb_insert_voucher(vid, "ADJ", 0, "P", rec.month_to, "월차결산 배치") < 0) { tpabort(0); return 1; }
    rec.closing_vid = vid;

    EXEC SQL DECLARE mc_cur CURSOR FOR
        SELECT acct, coalesce(sum(CASE WHEN dc = 'C' THEN amount ELSE -amount END), 0)
        FROM lg_ledger_line
        WHERE biz_date >= :h_from AND biz_date <= :h_to
          AND (acct = 'FEE_INC' OR acct = 'BADDEBT_EXP' OR acct LIKE 'FEE_DEPT%')
        GROUP BY acct ORDER BY acct;
    EXEC SQL OPEN mc_cur;
    if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }

    for (;;) {
        EXEC SQL FETCH mc_cur INTO :h_acct, :h_net;
        if (sqlca.sqlcode == 100) break;
        if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE mc_cur; tpabort(0); return 1; }
        if (h_net == 0) continue;
        mag = (h_net > 0) ? h_net : -h_net;
        /* 대변 잔액(수익)은 D 로, 차변 잔액(비용)은 C 로 소거 */
        if (lgdb_insert_line(vid, h_acct, (h_net > 0) ? "D" : "C", mag,
                             "", rec.month_to, "posted") < 0)
            { EXEC SQL CLOSE mc_cur; tpabort(0); return 1; }
        retained += h_net;
        rec.accts++;
    }
    EXEC SQL CLOSE mc_cur;

    /* 상대 라인: 순이익이면 C:RETAINED, 순손실이면 D:RETAINED -> 전표 균형 완성 */
    if (retained != 0) {
        mag = (retained > 0) ? retained : -retained;
        if (lgdb_insert_line(vid, "RETAINED", (retained > 0) ? "C" : "D", mag,
                             "", rec.month_to, "posted") < 0) { tpabort(0); return 1; }
    }
    rec.net_income = retained;

    if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
    printf(">>> lg_monthclose_batch COMMIT: [%s~%s] vid=%ld 손익계정 %ld개 순이익 %ld\n",
           rec.month_from, rec.month_to, rec.closing_vid, rec.accts, rec.net_income);

    tpclose(); tpterm();
    return 0;
}
