// Mock in-memory Firestore for jest tests.
// Reset via resetMockDb() in setupTests.js beforeEach.

const state = {
  docs: new Map(),        // path -> data
  subscribers: new Map(), // path -> Set<cb>
  counter: 0,
  calls: [],              // recorded SDK calls
};

export const MOCK_DB = {
  get(path) { return state.docs.has(path) ? clone(state.docs.get(path)) : null; },
  set(path, data) {
    state.docs.set(path, clone(data));
    this._notify(path);
  },
  merge(path, patch) {
    const cur = state.docs.has(path) ? state.docs.get(path) : {};
    const next = { ...cur, ...clone(patch) };
    state.docs.set(path, next);
    this._notify(path);
  },
  delete(path) {
    state.docs.delete(path);
    this._notify(path);
  },
  collection(collPath) {
    const out = [];
    for (const [p, data] of state.docs) {
      const parent = p.split('/').slice(0, -1).join('/');
      if (parent === collPath) out.push({ id: p.split('/').pop(), data: clone(data) });
    }
    return out;
  },
  subscribe(path, cb) {
    if (!state.subscribers.has(path)) state.subscribers.set(path, new Set());
    state.subscribers.get(path).add(cb);
    return () => state.subscribers.get(path)?.delete(cb);
  },
  _notify(path) {
    // notify exact doc path subscribers (wrapped in act for test isolation).
    // Set flag true around cb: testing-library asyncWrapper (waitFor) flips it
    // false during poll, which makes raw react act() warn 'not configured'.
    if (state.subscribers.has(path)) state.subscribers.get(path).forEach(cb => {
      try {
        const { act } = require('react');
        const prev = globalThis.IS_REACT_ACT_ENVIRONMENT;
        globalThis.IS_REACT_ACT_ENVIRONMENT = true;
        act(() => cb());
        globalThis.IS_REACT_ACT_ENVIRONMENT = prev;
      } catch {
        cb();
      }
    });
    // notify parent collection subscribers
    const parent = path.split('/').slice(0, -1).join('/');
    if (parent && state.subscribers.has(parent)) state.subscribers.get(parent).forEach(cb => {
      try {
        const { act } = require('react');
        const prev = globalThis.IS_REACT_ACT_ENVIRONMENT;
        globalThis.IS_REACT_ACT_ENVIRONMENT = true;
        act(() => cb());
        globalThis.IS_REACT_ACT_ENVIRONMENT = prev;
      } catch {
        cb();
      }
    });
  },
  nextId() { state.counter += 1; return String(state.counter).padStart(3, '0'); },
  _state: state,
};

export function recordCall(entry) {
  state.calls.push({ ...entry, ts: Date.now() });
}

export function resetMockDb() {
  state.docs.clear();
  state.subscribers.clear();
  state.calls.length = 0;
  state.counter = 0;
}

export function getCalls() {
  return [...state.calls];
}

function clone(v) {
  if (v === null || v === undefined) return v;
  return JSON.parse(JSON.stringify(v));
}
