import * as THREE from "three";
import { createHistoryWindowState, refreshHistoryWindow } from "./viewerHistory";
import type { HistoryWindowState } from "./viewerHudState";
import type { Selectable, WorldState } from "./viewerTypes";

export function openHistoryWindow(
  historyWindows: HistoryWindowState[],
  target: Selectable,
  nextCounter: number,
  bringToFront: (windowState: HistoryWindowState) => void,
  refreshWindows: () => void,
) {
  const existing = historyWindows.find((windowState) => JSON.stringify(windowState.target) === JSON.stringify(target));
  if (existing) {
    bringToFront(existing);
    refreshWindows();
    return nextCounter;
  }

  const windowState = createHistoryWindowState(target, historyWindows.length, nextCounter);
  historyWindows.push(windowState);
  bringToFront(windowState);
  refreshWindows();
  return nextCounter;
}

export function refreshHistoryWindows(
  world: WorldState | undefined,
  historyWindows: HistoryWindowState[],
  renderRecentEvents: (entityKind: string, entityId: string) => string,
  destroyWindow: (id: string) => void,
) {
  if (!world) {
    return;
  }

  for (const windowState of [...historyWindows]) {
    if (!refreshHistoryWindow(world, windowState, renderRecentEvents)) {
      destroyWindow(windowState.id);
    }
  }
}

export function destroyHistoryWindow(
  historyWindows: HistoryWindowState[],
  historyWindowDragId: string | undefined,
  historyWindowDragPointerId: number | undefined,
  id: string,
) {
  const index = historyWindows.findIndex((windowState) => windowState.id === id);
  if (index < 0) {
    return {
      historyWindowDragId,
      historyWindowDragPointerId,
    };
  }

  historyWindows.splice(index, 1);
  if (historyWindowDragId === id) {
    return {
      historyWindowDragId: undefined,
      historyWindowDragPointerId: undefined,
    };
  }

  return {
    historyWindowDragId,
    historyWindowDragPointerId,
  };
}

export function bringHistoryWindowToFront(windowState: HistoryWindowState, nextZIndex: number) {
  windowState.zIndex = nextZIndex;
}

export function beginHistoryWindowDrag(
  historyWindows: HistoryWindowState[],
  historyWindowDragOffset: THREE.Vector2,
  pointerId: number,
  windowId: string,
  clientX: number,
  clientY: number,
) {
  const windowState = historyWindows.find((candidate) => candidate.id === windowId);
  if (!windowState) {
    return {
      historyWindowDragId: undefined,
      historyWindowDragPointerId: undefined,
    };
  }

  historyWindowDragOffset.set(clientX - windowState.x, clientY - windowState.y);
  return {
    historyWindowDragId: windowId,
    historyWindowDragPointerId: pointerId,
  };
}

export function updateHistoryWindowDrag(
  historyWindows: HistoryWindowState[],
  historyWindowDragId: string | undefined,
  historyWindowDragPointerId: number | undefined,
  historyWindowDragOffset: THREE.Vector2,
  pointerId: number,
  clientX: number,
  clientY: number,
) {
  if (historyWindowDragPointerId !== pointerId || !historyWindowDragId) {
    return;
  }

  const windowState = historyWindows.find((candidate) => candidate.id === historyWindowDragId);
  if (!windowState) {
    return;
  }

  windowState.x = THREE.MathUtils.clamp(clientX - historyWindowDragOffset.x, 20, window.innerWidth - windowState.width - 20);
  windowState.y = THREE.MathUtils.clamp(clientY - historyWindowDragOffset.y, 20, window.innerHeight - windowState.height - 20);
}

export function endHistoryWindowDrag(
  _historyWindows: HistoryWindowState[],
  historyWindowDragId: string | undefined,
  historyWindowDragPointerId: number | undefined,
  pointerId: number,
) {
  if (historyWindowDragPointerId !== pointerId || !historyWindowDragId) {
    return {
      historyWindowDragId,
      historyWindowDragPointerId,
    };
  }

  return {
    historyWindowDragId: undefined,
    historyWindowDragPointerId: undefined,
  };
}

export async function copyTextToClipboard(text: string) {
  if (navigator.clipboard?.writeText) {
    try {
      await navigator.clipboard.writeText(text);
      return;
    } catch {
    }
  }

  const textarea = document.createElement("textarea");
  textarea.value = text;
  textarea.setAttribute("readonly", "true");
  textarea.style.position = "fixed";
  textarea.style.top = "0";
  textarea.style.left = "0";
  textarea.style.width = "1px";
  textarea.style.height = "1px";
  textarea.style.opacity = "0";
  document.body.append(textarea);
  textarea.focus();
  textarea.select();

  try {
    const copied = document.execCommand("copy");
    if (!copied) {
      throw new Error("execCommand copy failed");
    }
  } finally {
    textarea.remove();
  }
}
