import type { FilterOp, WhereRule } from '../transforms.schema';
import { isEmptyText, type Row } from '../row';

/**
 * filter — 按 where 规则保留行(等价 SQL WHERE 行级过滤)。
 *
 * where 是 AND 关系:所有字段规则都通过才保留。
 *
 * 规则:
 *   - not_empty: true   — 字段非 null/undefined/空字符串
 *   - in: [...]         — 字段值在列表中
 *   - equals: x         — 字段值等于 x
 */
export function runFilter(op: FilterOp, rows: Row[]): { rows: Row[]; dropped: number } {
  const out: Row[] = [];
  let dropped = 0;
  for (const row of rows) {
    if (passAll(row, op.where)) {
      out.push(row);
    } else {
      dropped++;
    }
  }
  return { rows: out, dropped };
}

/// "空"判定(给 where.empty 用):null/""/空白/"[]",或【空壳 JSON 数组】——
/// 数组元素全无实质内容(所有非 *Bak base64、非数组的标量字段都空)。
/// host EMR 常见占位行 [{treatName:"", toothPositionBak:"<base64>"}] 视为空,用于 gate "无结构化治疗"。
function isBlankValue(v: unknown): boolean {
  if (isEmptyText(v)) return true;
  if (typeof v !== 'string') return false;
  const t = v.trim();
  if (t === '[]') return true;
  if (!t.startsWith('[')) return false;
  try {
    const arr = JSON.parse(t);
    if (!Array.isArray(arr)) return false;
    const hasContent = arr.some(
      (el) =>
        el &&
        typeof el === 'object' &&
        Object.entries(el as Record<string, unknown>).some(
          ([k, val]) => !k.endsWith('Bak') && typeof val === 'string' && val.trim() !== '',
        ),
    );
    return !hasContent;
  } catch {
    return false;
  }
}

function passAll(row: Row, where: Record<string, WhereRule>): boolean {
  for (const [field, rule] of Object.entries(where)) {
    const v = row[field];
    if ('not_empty' in rule) {
      if (isEmptyText(v)) return false;
    } else if ('empty' in rule) {
      // 空:null/""/空白/"[]" 或【空壳 JSON 数组】(元素全无实质内容,如 host 占位行
      //   [{treatName:"",toothPosition:null,toothPositionBak:"<base64>"}])。
      // 用于 gate "无结构化治疗" — treat_plan 空壳时也应去 dispose 找治疗。
      if (!isBlankValue(v)) return false;
    } else if ('in' in rule) {
      const set = new Set(rule.in.map((x) => String(x)));
      if (!set.has(String(v))) return false;
    } else if ('equals' in rule) {
      if (String(v) !== String(rule.equals)) return false;
    }
  }
  return true;
}
