/**
 * 조건부 표시 규칙 평가 유틸
 *
 * [사용처]
 * - CanvasComponent.tsx : 캔버스 내 컴포넌트 조건부 표시
 * - ReportPreviewModal.tsx : 미리보기 시 조건부 표시
 * - ReportListPreviewModal.tsx : 목록 미리보기 시 조건부 표시
 */

import type { ConditionalRule } from "@/types/report";
export type { ConditionalRule };

type QueryResultGetter = (
  queryId: string
) => { fields: string[]; rows: Record<string, unknown>[] } | null;

/**
 * 단일 조건 규칙을 평가한다.
 * 쿼리 결과의 첫 번째 행에서 필드 값을 가져와 연산자로 비교한다.
 */
export function evaluateSingleRule(
  rule: ConditionalRule,
  getQueryResult: QueryResultGetter
): boolean {
  const queryResult = getQueryResult(rule.queryId);
  if (!queryResult?.rows?.length) return false;

  const rawValue = queryResult.rows[0][rule.field];
  const fieldStr =
    rawValue !== null && rawValue !== undefined ? String(rawValue) : "";
  const fieldNum = parseFloat(fieldStr);
  const compareNum = parseFloat(rule.value);

  switch (rule.operator) {
    case "eq":
      return fieldStr === rule.value;
    case "ne":
      return fieldStr !== rule.value;
    case "gt":
      return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum > compareNum;
    case "lt":
      return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum < compareNum;
    case "gte":
      return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum >= compareNum;
    case "lte":
      return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum <= compareNum;
    case "contains":
      return fieldStr.includes(rule.value);
    case "notEmpty":
      return fieldStr !== "";
    case "empty":
      return fieldStr === "";
    default:
      return false;
  }
}

/**
 * 다중 조건 규칙을 AND로 평가한다.
 * 모든 규칙이 충족되면 action에 따라 표시/숨김을 결정한다.
 */
export function evaluateConditionalRules(
  rules: ConditionalRule[] | undefined | null,
  getQueryResult: QueryResultGetter
): boolean {
  if (!rules || rules.length === 0) return true;

  const validRules = rules.filter(
    (r) => r.queryId && r.field && r.operator
  );
  if (validRules.length === 0) return true;

  const action = validRules[0].action || "show";
  const allMet = validRules.every((r) =>
    evaluateSingleRule(r, getQueryResult)
  );

  return action === "show" ? allMet : !allMet;
}
