import type { Post } from '../../core/entities/Post';

export function getEntityId(item: unknown): string | null {
  if (!item || typeof item !== 'object') return null;
  const maybeId = (item as { id?: unknown }).id;
  if (typeof maybeId === 'string' || typeof maybeId === 'number') return String(maybeId);
  return null;
}

export function mergePostListWithFastPath(
  previousInput: Post[] | null | undefined,
  incomingInput: Post[] | null | undefined
): Post[] {
  const previous = Array.isArray(previousInput) ? previousInput : [];
  const incoming = Array.isArray(incomingInput) ? incomingInput : [];
  if (incoming.length === 0) return previous;
  if (previous.length === 0) return incoming;

  const lastPrevId = getEntityId(previous[previous.length - 1]);
  const firstIncomingId = getEntityId(incoming[0]);
  if (lastPrevId && firstIncomingId && lastPrevId !== firstIncomingId) {
    const prevIdSet = new Set(
      previous.map(item => getEntityId(item)).filter(Boolean) as string[]
    );
    if (!prevIdSet.has(firstIncomingId)) return [...previous, ...incoming];
  }

  const merged = [...previous];
  const indexById = new Map<string, number>();
  for (let i = 0; i < merged.length; i += 1) {
    const id = getEntityId(merged[i]);
    if (id) indexById.set(id, i);
  }

  for (const post of incoming) {
    const id = getEntityId(post);
    if (!id) { merged.push(post); continue; }
    const existingIndex = indexById.get(id);
    if (existingIndex === undefined) {
      indexById.set(id, merged.length);
      merged.push(post);
    } else {
      merged[existingIndex] = post;
    }
  }
  return merged;
}

export function mergeRefreshWindow(
  previousInput: Post[] | null | undefined,
  latestInput: Post[] | null | undefined
): Post[] {
  const previous = Array.isArray(previousInput) ? previousInput : [];
  const latest = Array.isArray(latestInput) ? latestInput : [];
  if (latest.length === 0) return previous;
  if (previous.length === 0) return latest;

  const latestIdSet = new Set(
    latest.map(item => getEntityId(item)).filter(Boolean) as string[]
  );
  const remaining = previous.filter(item => {
    const id = getEntityId(item);
    return !id || !latestIdSet.has(id);
  });
  return [...latest, ...remaining];
}
