export interface FieldDiff {
  path: string;
  oldValue: unknown;
  newValue: unknown;
}

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

export function fieldDiff(a: unknown, b: unknown, path = ''): FieldDiff[] {
  if (Object.is(a, b)) return [];

  if (isPlainObject(a) && isPlainObject(b)) {
    const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
    const out: FieldDiff[] = [];
    for (const k of keys) {
      const sub = path ? `${path}.${k}` : k;
      out.push(...fieldDiff(a[k], b[k], sub));
    }
    return out;
  }

  if (Array.isArray(a) && Array.isArray(b)) {
    const len = Math.max(a.length, b.length);
    const out: FieldDiff[] = [];
    for (let i = 0; i < len; i++) {
      out.push(...fieldDiff(a[i], b[i], `${path}[${i}]`));
    }
    return out;
  }

  return [{ path: path || '(root)', oldValue: a, newValue: b }];
}
