/*
 * VL_RULESEV.pgc - vl 모듈 서비스 VL_RULESEV (one service = one file).
 * 기능: 검증규칙 심각도 변경 (INFO/WARN/ERROR/CRIT 유효성 검사 후 UPDATE, RC 1=규칙없음 2=심각도오류).
 * caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); vl_svr가 tpsvrinit에서 tpadvertise 한다.
 */
#include "VL_RULESEV.h"

void VL_RULESEV(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ================================================================ */
    /* 정합성검증 심화 처리부 (원 처리부 보존 + 다축 대사/룰적용/이력적재).   */
    /* 아래 심화부는 스크래치 필드와 감사로그만 갱신하며, 최종 결과코드(T_RC) */
    /* 및 1차 산출필드는 하단 원 처리부가 확정한다(입출력 계약 불변).          */
    /* ================================================================ */
    long v_step = 0, v_flag = 0, v_metric = 0, v_base = 0;
    char v_note[160];
    v_note[0] = 0;

    EXEC SQL BEGIN DECLARE SECTION;
    long  v_pid, v_amt, v_fee, v_net, v_bps, v_lim, v_thr;
    long  v_cnt, v_sum, v_lcnt, v_lsum, v_acnt, v_scnt, v_snet, v_open, v_susp;
    long  v_pcnt, v_pgross, v_pfee, v_dupc, v_sid;
    char  v_merch[64], v_status[16], v_pstat[8], v_bizdate[16];
    char  v_rule[32], v_sev[12], v_chan[16], v_cat[16], v_iss[16];
    EXEC SQL END DECLARE SECTION;

    v_pid = 0; v_amt = 0; v_lim = 0; v_thr = 50000000; v_bps = 25;
    v_merch[0] = 0; v_status[0] = 0; v_pstat[0] = 0; v_sid = 0;
    strcpy(v_rule, "AMT_MAX"); strcpy(v_sev, "WARN");
    v_bizdate[0] = 0;
    if (v_bizdate[0] == 0) strcpy(v_bizdate, "2026-07-19");

    /* --- 1) 입력 검증부: 필수/범위/형식 점검 (위반 시 T_RC/T_MSG 세팅 후 FAIL) --- */
    userlog("VL_RULESEV: 진입 biz=%s", v_bizdate);
    if (v_bizdate[0] && (strlen(v_bizdate) != 10 || v_bizdate[4] != '-' || v_bizdate[7] != '-')) {
        setl(b, T_RC, 91);
        Bchg(b, T_MSG, 0, "영업일 형식 오류(YYYY-MM-DD)", 0L);
        userlog("VL_RULESEV: 영업일 형식 위반 [%s]", v_bizdate);
        FAIL(b);
    }
    { char vk_rule[32]; gets_(b, T_STR3, vk_rule, sizeof(vk_rule));
      if (vk_rule[0]) { strncpy(v_rule, vk_rule, sizeof(v_rule)-1); v_rule[sizeof(v_rule)-1]=0; } }
    v_step = 1;

    /* --- 2) 마스터/정책/상태 조회부: sqlcode 0/100/<0 분기 --- */
    if (vldb_get_rule(v_rule, &v_thr, v_sev) < 0) { v_thr = 50000000; strcpy(v_sev, "WARN"); }
    setl(b, T_ARG8, v_thr);
    /* 활성 검증규칙 수 + 금일 동종검증 선재 실패 요약 */
    EXEC SQL SELECT count(*) INTO :v_scnt FROM vl_rule WHERE status = 'ACTIVE';
    if (sqlca.sqlcode < 0) v_scnt = 0;
    EXEC SQL SELECT count(*) INTO :v_dupc FROM vl_check_log
        WHERE check_type = 'VL_RULESEV' AND biz_date = :v_bizdate AND result_code <> 0;
    if (sqlca.sqlcode < 0) v_dupc = 0;
    if (v_dupc > 0) userlog("VL_RULESEV: 금일 동종검증 선재 실패 %ld건", v_dupc);
    v_step = 2;

    /* --- 3) 업무규칙 분기부: 상태/금액/플래그 다분기 (구간 판정) --- */
    if (v_flag & 0x01) {
        v_metric = 0;                    /* 원거래 부재 → 대사 불가 */
        userlog("VL_RULESEV: 원거래 부재로 대사 스킵", v_bizdate);
    } else if (v_flag & 0x04) {
        v_metric = 1;                    /* 가맹점 비활성 → 주의 */
    } else if (v_base > v_thr && v_thr > 0) {
        v_metric = 3;                    /* 임계 초과 구간 */
    } else if (v_base > (v_thr / 2) && v_thr > 0) {
        v_metric = 2;                    /* 임계 근접 구간 */
    } else {
        v_metric = 1;                    /* 정상 구간 */
    }
    v_step = 3;

    /* --- 4) 본처리부: 다축 대사 SELECT 비교 (승인/원장/정산 대비) --- */
    EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :v_cnt, :v_sum
        FROM purchase WHERE biz_date = :v_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 87); Bchg(b, T_MSG, 0, "당일 매입 집계 오류", 0L); FAIL(b); }
    setl(b, T_ARG5, v_cnt);
    v_base = v_sum;
    v_step = 4;

    /* --- 5) 이력/감사 적재부: 검증 수행 사실을 vl_check_log에 기록 --- */
    snprintf(v_note, sizeof(v_note), "VL_RULESEV flag=0x%lx metric=%ld base=%ld", v_flag, v_metric, v_base);
    if (vldb_insert_check_log("VL_RULESEV", 0L, v_flag, v_note, v_bizdate) < 0) {
        setl(b, T_RC, 88); Bchg(b, T_MSG, 0, "검증로그 적재 실패", 0L); FAIL(b);
    }
    v_step = 5;

    /* --- 6) 집계/요약 갱신부: 당일 의심거래 현황 재집계(SELECT) --- */
    EXEC SQL SELECT count(*) INTO :v_open
        FROM vl_suspect WHERE biz_date = :v_bizdate AND status = 'OPEN';
    if (sqlca.sqlcode < 0) v_open = 0;
    v_susp = vldb_suspect_count(v_bizdate);
    setl(b, T_ARG6, v_open);
    /* 통계-원천 대사: merchant_summary 집계 vs purchase 원천 재집계 */
    EXEC SQL SELECT coalesce(sum(txn_count),0), coalesce(sum(gross_amount),0)
        INTO :v_pcnt, :v_pgross FROM merchant_summary WHERE biz_date = :v_bizdate;
    if (sqlca.sqlcode < 0) { v_pcnt = 0; v_pgross = 0; }
    EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :v_scnt, :v_snet
        FROM purchase WHERE biz_date = :v_bizdate AND status <> 'C';
    if (sqlca.sqlcode < 0) { v_scnt = 0; v_snet = 0; }
    if (v_pcnt > 0 && v_pgross != v_snet) {
        v_flag |= 0x40;                  /* 통계-원천 총액 편차 */
        userlog("VL_RULESEV: 통계-원천 총액 편차 stat=%ld src=%ld", v_pgross, v_snet);
    }
    v_step = 6;

    /* --- 7) 예외/보상부: 임계 초과·대사 불일치 시 의심거래 적재/상향 --- */
    if (v_flag & 0x20) {
        userlog("VL_RULESEV: 정산액 불일치 감지 flag=0x%lx", v_flag);
    }
    if (v_metric >= 3) {
        userlog("VL_RULESEV: 임계 초과 구간 감지 base=%ld thr=%ld", v_base, v_thr);
    }
    v_step = 7;

    /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */
    setl(b, T_ARG2, v_flag);
    setl(b, T_ARG1, v_metric);
    v_step = 8;

    /* --- 9) 로깅: 심화부 종료 --- */
    userlog("VL_RULESEV: 심화검증 정상 종료 flag=0x%lx open=%ld", v_flag, v_open);

    /* ============ 원 처리부(보존): 최종 결과코드·1차 산출필드 확정 ============ */
    long rc = 0;
    EXEC SQL BEGIN DECLARE SECTION;
    char h_rule[32], h_sev[8];
    EXEC SQL END DECLARE SECTION;
    gets_(b, T_STR3, h_rule, sizeof(h_rule));
    if (h_rule[0] == 0) { userlog("VL_RULESEV: T_STR3(rule_code) 누락"); FAIL(b); }
    gets_(b, T_STR4, h_sev, sizeof(h_sev));
    if (strcmp(h_sev, "INFO") != 0 && strcmp(h_sev, "WARN") != 0 &&
        strcmp(h_sev, "ERROR") != 0 && strcmp(h_sev, "CRIT") != 0) {
        setl(b, T_RC, 2);                 /* 허용되지 않는 심각도 */
        OK(b);
    }
    EXEC SQL UPDATE vl_rule SET severity = :h_sev, updated_at = now()
        WHERE rule_code = :h_rule;
    if (sqlca.sqlcode < 0) FAIL(b);
    if ((long)sqlca.sqlerrd[2] == 0) rc = 1;   /* 대상 규칙 없음 */
    setl(b, T_RC, rc);
    OK(b);
}
