/*
 * acq_clrfile.c - 클리어링(정산) 파일 생성기 (아웃바운드 프레젠트먼트).
 *   카드망과 배치로 주고받는 실제 정산파일을 재현. cl_presentment 에서 당일
 *   프레젠트먼트 레코드를 읽어 고정폭 레코드로 /app/out/ 에 파일 산출 후
 *   cl_clearing_file 에 등록. 실제 매입시스템의 SFTP 배치 파일교환 대역.
 *   레코드(고정폭 80): TYPE(2) PRESENT_ID(12) PURCHASE_ID(12) SCHEME(4)
 *                      CLEARING_AMT(15) PRESENT_DATE(8) MSG_CLASS(15) STATUS(12)
 *   사용법: acq_clrfile <biz_date YYYY-MM-DD> [outdir]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libpq-fe.h>

int main(int argc, char **argv) {
    const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
    const char *outdir  = (argc > 2) ? argv[2] : "/app/out";

    const char *ci = getenv("PGCONN");
    PGconn *c = PQconnectdb(ci ? ci : "host=db user=acq password=acq dbname=acq");
    if (PQstatus(c) != CONNECTION_OK) { fprintf(stderr, "PG 연결실패: %s\n", PQerrorMessage(c)); return 1; }

    char q[512];
    snprintf(q, sizeof(q),
      "SELECT presentment_id, purchase_id, scheme, clearing_amt, "
      "to_char(present_date,'YYYYMMDD'), msg_class, status "
      "FROM cl_presentment WHERE present_date = '%s' ORDER BY presentment_id", bizdate);
    PGresult *r = PQexec(c, q);
    if (PQresultStatus(r) != PGRES_TUPLES_OK) { fprintf(stderr, "조회실패: %s\n", PQerrorMessage(c)); return 1; }
    int n = PQntuples(r);

    char path[512];
    char dcompact[16]; int j = 0;
    for (const char *p = bizdate; *p; p++) if (*p != '-') dcompact[j++] = *p;
    dcompact[j] = 0;
    snprintf(path, sizeof(path), "%s/CLR_BC_%s.dat", outdir, dcompact);

    /* outdir 보장 */
    char mkd[600]; snprintf(mkd, sizeof(mkd), "mkdir -p %s", outdir); if (system(mkd) != 0) {}

    FILE *f = fopen(path, "w");
    if (!f) { fprintf(stderr, "파일열기 실패: %s\n", path); return 1; }

    /* 헤더 레코드 */
    fprintf(f, "HD%-12s%-12s%-4s%15s%-8s%-15s%-12s\n",
            "CLEARINGFILE", "", "BC", "", dcompact, "PRESENTMENT", "HEADER");

    long total = 0; unsigned long chk = 0;
    for (int i = 0; i < n; i++) {
        long pres = atol(PQgetvalue(r, i, 0));
        long pid  = atol(PQgetvalue(r, i, 1));
        const char *sc = PQgetvalue(r, i, 2);
        long amt = atol(PQgetvalue(r, i, 3));
        const char *pd = PQgetvalue(r, i, 4);
        const char *mc = PQgetvalue(r, i, 5);
        const char *st = PQgetvalue(r, i, 6);
        fprintf(f, "DT%012ld%012ld%-4s%015ld%-8s%-15s%-12s\n", pres, pid, sc, amt, pd, mc, st);
        total += amt; chk = (chk * 131 + (unsigned long)amt) & 0xFFFFFFFF;
    }
    /* 트레일러: 건수·합계·체크섬 */
    fprintf(f, "TR%012d%015ld%08lX%43s\n", n, total, chk, "");
    fclose(f);

    /* 레지스트리 등록 */
    char reg[900];
    snprintf(reg, sizeof(reg),
      "INSERT INTO cl_clearing_file(file_id,direction,filename,scheme,biz_date,"
      "rec_count,total_amount,checksum,status) VALUES "
      "(nextval('cl_file_seq'),'OUT','CLR_BC_%s.dat','BC','%s',%d,%ld,'%08lX','GENERATED') "
      "ON CONFLICT DO NOTHING", dcompact, bizdate, n, total, chk);
    PGresult *ir = PQexec(c, reg); PQclear(ir);
    PQclear(r);

    printf(">>> 클리어링 파일 생성: %s (레코드 %d · 합계 %ld · 체크섬 %08lX)\n", path, n, total, chk);
    PQfinish(c);
    return 0;
}
