/*
 * lg_balance_dbio.pgc - 계정/가맹점 잔액 재계산 및 upsert (part of liblgdbio.a).
 * ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
 * 복식부기 원칙: balance = 차변(D) 합 - 대변(C) 합.
 */
#include <string.h>
#include <userlog.h>
#include "lg_dbio.h"

/* 계정과목 x 영업일 잔액을 원장 라인에서 재집계하여 upsert. */
int lgdb_recalc_acct_bal(const char *acct, const char *bizdate)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_acct[32], h_bizdate[16];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_acct, acct, sizeof(h_acct) - 1);        h_acct[sizeof(h_acct)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1);  h_bizdate[sizeof(h_bizdate)-1] = 0;

    EXEC SQL INSERT INTO lg_account_bal (acct, biz_date, debit_total, credit_total, balance)
        SELECT :h_acct, :h_bizdate,
               coalesce(sum(CASE WHEN dc = 'D' THEN amount ELSE 0 END), 0),
               coalesce(sum(CASE WHEN dc = 'C' THEN amount ELSE 0 END), 0),
               coalesce(sum(CASE WHEN dc = 'D' THEN amount ELSE -amount END), 0)
        FROM lg_ledger_line
        WHERE acct = :h_acct AND biz_date = :h_bizdate
        ON CONFLICT (acct, biz_date) DO UPDATE
        SET debit_total  = EXCLUDED.debit_total,
            credit_total = EXCLUDED.credit_total,
            balance      = EXCLUDED.balance,
            updated_at   = now();
    if (sqlca.sqlcode < 0) {
        userlog("lgdb_recalc_acct_bal FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    return 0;
}

int lgdb_get_acct_bal(const char *acct, const char *bizdate, long *bal_out)
{
    EXEC SQL BEGIN DECLARE SECTION;
    long h_bal;
    char h_acct[32], h_bizdate[16];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_acct, acct, sizeof(h_acct) - 1);        h_acct[sizeof(h_acct)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1);  h_bizdate[sizeof(h_bizdate)-1] = 0;

    EXEC SQL SELECT balance INTO :h_bal FROM lg_account_bal
        WHERE acct = :h_acct AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
        userlog("lgdb_get_acct_bal FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    *bal_out = h_bal;
    return 0;
}

int lgdb_upsert_acct_bal(const char *acct, const char *bizdate, long debit, long credit)
{
    EXEC SQL BEGIN DECLARE SECTION;
    long h_debit = debit, h_credit = credit, h_bal = debit - credit;
    char h_acct[32], h_bizdate[16];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_acct, acct, sizeof(h_acct) - 1);        h_acct[sizeof(h_acct)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1);  h_bizdate[sizeof(h_bizdate)-1] = 0;

    EXEC SQL INSERT INTO lg_account_bal (acct, biz_date, debit_total, credit_total, balance)
        VALUES (:h_acct, :h_bizdate, :h_debit, :h_credit, :h_bal)
        ON CONFLICT (acct, biz_date) DO UPDATE
        SET debit_total  = lg_account_bal.debit_total + EXCLUDED.debit_total,
            credit_total = lg_account_bal.credit_total + EXCLUDED.credit_total,
            balance      = lg_account_bal.balance + EXCLUDED.balance,
            updated_at   = now();
    if (sqlca.sqlcode < 0) {
        userlog("lgdb_upsert_acct_bal FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    return 0;
}

/* 가맹점 x 영업일 잔액을 원장 라인에서 재집계하여 upsert. */
int lgdb_upsert_merch_bal(const char *merch, const char *bizdate)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_merch[64], h_bizdate[16];
    EXEC SQL END DECLARE SECTION;

    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;

    EXEC SQL INSERT INTO lg_merch_bal (merchant_id, biz_date, debit_total, credit_total, balance)
        SELECT :h_merch, :h_bizdate,
               coalesce(sum(CASE WHEN dc = 'D' THEN amount ELSE 0 END), 0),
               coalesce(sum(CASE WHEN dc = 'C' THEN amount ELSE 0 END), 0),
               coalesce(sum(CASE WHEN dc = 'D' THEN amount ELSE -amount END), 0)
        FROM lg_ledger_line
        WHERE merchant_id = :h_merch AND biz_date = :h_bizdate
        ON CONFLICT (merchant_id, biz_date) DO UPDATE
        SET debit_total  = EXCLUDED.debit_total,
            credit_total = EXCLUDED.credit_total,
            balance      = EXCLUDED.balance,
            updated_at   = now();
    if (sqlca.sqlcode < 0) {
        userlog("lgdb_upsert_merch_bal FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    return 0;
}
