import {
  captureLivePreviewTargets,
  type LivePreviewMode,
  type LivePreviewSession,
  type LivePreviewTarget,
} from "./timelineLivePreview.js";

function isHTMLElement(value: EventTarget | null | undefined): value is HTMLElement {
  return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
}

function resolveAllocationPreviewRoot(currentTarget: EventTarget | null | undefined): HTMLElement | null {
  return isHTMLElement(currentTarget)
    ? currentTarget.closest<HTMLElement>('[data-timeline-drag-preview~="allocation"]')
    : null;
}

function createLivePreviewSession(
  mode: LivePreviewMode,
  cellWidth: number,
  targets: LivePreviewTarget[],
): LivePreviewSession | null {
  if (targets.length === 0) return null;

  return {
    mode,
    cellWidth,
    targets,
    pointerDeltaX: 0,
    daysDelta: 0,
    frame: null,
  };
}

export function createProjectPreviewSession({
  projectId,
  currentTarget,
  cellWidth,
  queryProjectTargets = (nextProjectId: string) =>
    document.querySelectorAll<HTMLElement>(
      `[data-timeline-drag-preview~="project-shift"][data-timeline-project-id="${nextProjectId}"]`,
    ),
  isElement = isHTMLElement,
}: {
  projectId: string;
  currentTarget?: EventTarget | null | undefined;
  cellWidth: number;
  queryProjectTargets?: (projectId: string) => Iterable<HTMLElement>;
  isElement?: (value: EventTarget | null | undefined) => value is HTMLElement;
}): LivePreviewSession | null {
  const targets = captureLivePreviewTargets(queryProjectTargets(projectId));
  if (targets.length === 0 && isElement(currentTarget)) {
    targets.push(...captureLivePreviewTargets([currentTarget]));
  }

  return createLivePreviewSession("move", cellWidth, targets);
}

export function createAllocationPreviewSession({
  currentTarget,
  mode = "move",
  cellWidth,
  resolveAllocationRoot = resolveAllocationPreviewRoot,
}: {
  currentTarget?: EventTarget | null | undefined;
  mode?: LivePreviewMode;
  cellWidth: number;
  resolveAllocationRoot?: (currentTarget: EventTarget | null | undefined) => HTMLElement | null;
}): LivePreviewSession | null {
  const root = resolveAllocationRoot(currentTarget);
  const targets = root ? captureLivePreviewTargets([root]) : [];
  return createLivePreviewSession(mode, cellWidth, targets);
}
