import type { InferenceResult, Settings } from "../shared/types";

const HIDDEN = "data-vibeguard-hidden";
const ORIGINAL_DISPLAY = "data-vibeguard-original-display";
const PLACEHOLDER = "data-vibeguard-placeholder";
const PLACEHOLDER_FOR = "data-vibeguard-placeholder-for";

export interface FilterOptions {
  postId?: string;
  onShow?: () => void;
}

export function applyResult(element: Element, result: InferenceResult, settings: Settings, options: FilterOptions = {}): void {
  const shouldFilter = result.label === "toxic" && result.probability >= settings.threshold;
  const postId = options.postId ?? result.id;
  if (!shouldFilter) { restore(element, postId); return; }

  element.setAttribute(HIDDEN, "true");
  const html = element as HTMLElement;
  if (!html.hasAttribute(ORIGINAL_DISPLAY)) html.setAttribute(ORIGINAL_DISPLAY, html.style.display);
  html.style.display = "none";
  if (settings.filterMode === "hide") {
    return;
  }

  let placeholder = ownedPlaceholderAfter(element, postId);
  if (!placeholder) {
    placeholder = document.createElement("div");
    placeholder.setAttribute(PLACEHOLDER, "true");
    placeholder.setAttribute(PLACEHOLDER_FOR, postId);
    element.insertAdjacentElement("afterend", placeholder);
  }
  placeholder.className = "vibeguard-placeholder";
  const message = `Content hidden as toxic${settings.showScore ? ` (${Math.round(result.probability * 100)}%)` : ""}`;
  const button = document.createElement("button");
  button.type = "button";
  button.textContent = "Show";
  button.addEventListener("click", () => {
    if (options.onShow) options.onShow();
    else restore(element, postId);
  });
  placeholder.replaceChildren(message, " ", button);
}

export function hasAppliedFilter(element: Element, postId: string, settings: Settings): boolean {
  const html = element as HTMLElement;
  return element.getAttribute(HIDDEN) === "true" && html.style.display === "none"
    && (settings.filterMode === "hide" || ownedPlaceholderAfter(element, postId) !== undefined);
}

export function restore(element: Element, postId?: string): void {
  const html = element as HTMLElement;
  html.style.display = html.getAttribute(ORIGINAL_DISPLAY) ?? "";
  html.removeAttribute(ORIGINAL_DISPLAY);
  element.removeAttribute(HIDDEN);
  const placeholder = element.nextElementSibling;
  if (placeholder?.hasAttribute(PLACEHOLDER) && (!postId || placeholder.getAttribute(PLACEHOLDER_FOR) === postId)) placeholder.remove();
}

export function removeOrphanedPlaceholders(postId: string, elements: Iterable<Element>): void {
  const currentElements = new Set(elements);
  document.querySelectorAll(`[${PLACEHOLDER_FOR}]`).forEach((placeholder) => {
    if (placeholder.getAttribute(PLACEHOLDER_FOR) !== postId) return;
    if (!currentElements.has(placeholder.previousElementSibling as Element)) placeholder.remove();
  });
}

function ownedPlaceholderAfter(element: Element, postId: string): Element | undefined {
  const placeholder = element.nextElementSibling;
  return placeholder?.hasAttribute(PLACEHOLDER) && placeholder.getAttribute(PLACEHOLDER_FOR) === postId ? placeholder : undefined;
}
