"use client";

import {
  Fragment,
  memo,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import { Lab1ConfidenceChat } from "~/components/labs/Lab1ConfidenceChat";
import { Lab1NetronPanel } from "~/components/labs/Lab1NetronPanel";
import { Lab3TerminalFrame } from "~/components/labs/Lab3TerminalFrame";
import { Lab8Chat } from "~/components/labs/Lab8Chat";
import { Objective5Chat } from "~/components/labs/Objective5Chat";
import { QuantizationGridExplorer } from "~/components/labs/QuantizationGridExplorer";
import { QuantizationExplorer } from "~/components/labs/QuantizationExplorer";
import { TokenizerPlaygroundEmbed } from "~/components/labs/TokenizerPlaygroundEmbed";
import {
  fetchCoursewareRuntimeConfig,
  isCoursewareServiceId,
  normalizeCoursewareRuntimeConfig,
  resolveCoursewareServiceAddress,
  resolveCoursewareServiceUrl,
  type ResolvedCoursewareRuntimeConfig,
} from "~/lib/courseware-runtime";

type LabContentProps = {
  className: string;
  html: string;
};

type LabContentArticleProps = LabContentProps & {
  onZoomImage: (image: ZoomedImageState) => void;
};

const cliLanguagePattern =
  /\b(language-(bash|sh|shell|zsh|console|terminal)|bash|shell|zsh)\b/i;
const cliCommandPattern =
  /(^|\n)\s*(\$|sudo\s|git\s|python3?\s|pip\s|npm\s|pnpm\s|yarn\s|llama-|ollama\s|curl\s|wget\s|apt\s|cd\s|ls\s|cat\s|cp\s|mv\s|chmod\s|make\s)/i;
const promptLanguagePattern =
  /\b(language-(text|plaintext|md|markdown)|text|plaintext|markdown)\b/i;
const promptSignalPattern =
  /\b(you are|guidelines|follow these|example|when provided|system prompt|tasked with)\b/i;

type ParsedSetting = {
  key: string;
  value: string;
};

type ZoomedImageState = {
  src: string;
  alt: string;
};

const quantizationExplorerToken = "<div data-quantization-explorer></div>";
const quantizationGridExplorerToken =
  "<div data-quantization-grid-explorer></div>";
const objective5ChatToken = "<div data-objective5-chat></div>";
const lab8ChatToken = "<div data-lab8-chat></div>";
const lab3TerminalToken = "<div data-lab3-terminal></div>";
const lab1ConfidenceToken = "<div data-lab1-confidence></div>";
const lab1NetronToken = "<div data-lab1-netron-panel></div>";
const tokenizerPlaygroundToken = "<div data-tokenizer-playground></div>";
const serviceTokenPattern =
  /\{\{service-(url|address):([a-z0-9-]+)(?::([^}]+))?\}\}/g;
const serviceLabels: Record<string, string> = {
  chunkviz: "ChunkViz",
  "embedding-atlas": "Embedding Atlas",
  "open-webui": "Open WebUI",
  promptfoo: "Promptfoo",
  ssh: "SSH",
  unsloth: "Unsloth",
};

function looksLikeCliCommand(commandText: string, className: string) {
  if (cliLanguagePattern.test(className)) return true;
  return (
    cliCommandPattern.test(commandText) || /--[a-z0-9-]+/i.test(commandText)
  );
}

function looksLikePromptTextBlock(text: string, className: string) {
  if (looksLikeCliCommand(text, className)) return false;

  const normalizedText = text.trim();
  if (!normalizedText) return false;

  const lineCount = normalizedText.split("\n").length;
  if (promptLanguagePattern.test(className) && normalizedText.length > 80)
    return true;
  if (lineCount >= 4 && promptSignalPattern.test(normalizedText)) return true;
  if (lineCount >= 6 && /(^|\n)\s*[*-]\s+/.test(normalizedText)) return true;
  return false;
}

function escapeRegex(value: string) {
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function escapeHtml(value: string) {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

function parseSettingListItem(item: HTMLLIElement): ParsedSetting | null {
  const keyElement = item.querySelector("code");
  if (!keyElement) return null;

  const key = (keyElement.textContent ?? "").replace(/\s+/g, " ").trim();
  if (!key || key.length > 40) return null;

  const text = (item.textContent ?? "").replace(/\s+/g, " ").trim();
  const match = new RegExp(
    `^${escapeRegex(key)}\\s*(?:-|–|—|:|=)\\s*(.+)$`,
  ).exec(text);
  if (!match) return null;

  const value = (match[1] ?? "").replace(/\s+/g, " ").trim();
  if (!value || value.length > 36) return null;
  if (/[.;]/.test(value) && value.length > 16) return null;

  return { key, value };
}

function enhanceSettingsLists(root: HTMLElement) {
  const lists = root.querySelectorAll<HTMLUListElement>("ul");

  for (const list of lists) {
    if (list.dataset.settingsEnhanced === "true") continue;

    const items = Array.from(list.children).filter(
      (node): node is HTMLLIElement => {
        return node.tagName === "LI";
      },
    );
    if (items.length < 2) continue;

    const parsedItems = items.map((item) => parseSettingListItem(item));
    if (parsedItems.some((parsedItem) => parsedItem === null)) continue;

    const settings = parsedItems as ParsedSetting[];
    const compactValueCount = settings.filter(
      (setting) => setting.value.length <= 20,
    ).length;
    if (compactValueCount < Math.max(2, Math.ceil(settings.length * 0.66)))
      continue;

    list.dataset.settingsEnhanced = "true";
    list.classList.add("lab-settings-list");

    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      const setting = settings[i];
      if (!item || !setting) continue;

      item.classList.add("lab-settings-item");
      item.innerHTML =
        `<span class="lab-setting-key">${escapeHtml(setting.key)}</span>` +
        `<span class="lab-setting-value">${escapeHtml(setting.value)}</span>`;
    }
  }
}

function ensureCopyButton(pre: HTMLPreElement, label: string) {
  if (pre.dataset.copyEnhanced === "true") return;

  pre.dataset.copyEnhanced = "true";
  const copyButton = document.createElement("button");
  copyButton.type = "button";
  copyButton.className = "lab-copy-button";
  copyButton.textContent = label;
  copyButton.dataset.defaultLabel = label;
  copyButton.setAttribute("aria-label", "Copy block to clipboard");
  pre.appendChild(copyButton);
}

async function copyTextToClipboard(text: string) {
  if (window.isSecureContext && navigator.clipboard?.writeText) {
    await navigator.clipboard.writeText(text);
    return;
  }

  const activeElement =
    document.activeElement instanceof HTMLElement
      ? document.activeElement
      : null;
  const selection = document.getSelection();
  const previousRanges =
    selection && selection.rangeCount > 0
      ? Array.from({ length: selection.rangeCount }, (_, index) =>
          selection.getRangeAt(index).cloneRange(),
        )
      : [];

  const textarea = document.createElement("textarea");
  textarea.value = text;
  textarea.setAttribute("readonly", "");
  textarea.setAttribute("aria-hidden", "true");
  textarea.style.position = "fixed";
  textarea.style.top = "0";
  textarea.style.left = "-9999px";
  textarea.style.opacity = "0";
  textarea.style.pointerEvents = "none";

  document.body.appendChild(textarea);
  textarea.focus();
  textarea.select();
  textarea.setSelectionRange(0, textarea.value.length);

  try {
    const didCopy = document.execCommand("copy");
    if (!didCopy) {
      throw new Error("Copy command was rejected");
    }
  } finally {
    document.body.removeChild(textarea);
    if (selection) {
      selection.removeAllRanges();
      for (const range of previousRanges) {
        selection.addRange(range);
      }
    }
    activeElement?.focus();
  }
}

function enhanceHarnessSelectors(root: HTMLElement) {
  const harnessButtons = Array.from(
    root.querySelectorAll<HTMLButtonElement>("button[data-harness-choice]"),
  );
  const harnessBranches = Array.from(
    root.querySelectorAll<HTMLElement>("[data-harness-branch]"),
  );

  if (harnessButtons.length === 0 || harnessBranches.length === 0) {
    return () => {};
  }

  const supportedHarnesses = new Set(
    harnessButtons
      .map((button) => button.dataset.harnessChoice?.trim())
      .filter((value): value is string => Boolean(value)),
  );

  let selectedHarness: string | null = null;

  const syncHarnessSelection = () => {
    for (const button of harnessButtons) {
      const harnessId = button.dataset.harnessChoice?.trim() ?? "";
      const isSelected =
        selectedHarness !== null && harnessId === selectedHarness;
      button.setAttribute("aria-pressed", isSelected ? "true" : "false");
      button.dataset.selected = isSelected ? "true" : "false";
    }

    for (const branch of harnessBranches) {
      const harnessId = branch.dataset.harnessBranch?.trim() ?? "";
      const shouldHide =
        selectedHarness === null || harnessId !== selectedHarness;
      branch.hidden = shouldHide;
      branch.setAttribute("aria-hidden", shouldHide ? "true" : "false");
    }
  };

  syncHarnessSelection();

  const handleHarnessClick = (event: Event) => {
    const target = event.target as HTMLElement;
    const button = target.closest<HTMLButtonElement>(
      "button[data-harness-choice]",
    );
    if (!button || !root.contains(button)) return;

    const harnessId = button.dataset.harnessChoice?.trim() ?? "";
    if (!supportedHarnesses.has(harnessId)) return;

    event.preventDefault();
    selectedHarness = selectedHarness === harnessId ? null : harnessId;
    syncHarnessSelection();
  };

  root.addEventListener("click", handleHarnessClick);
  return () => {
    root.removeEventListener("click", handleHarnessClick);
  };
}

function resolveServiceTokenValue(
  runtimeConfig: ResolvedCoursewareRuntimeConfig,
  tokenType: string,
  serviceId: string,
  pathSuffix?: string,
) {
  if (!isCoursewareServiceId(serviceId)) {
    return null;
  }

  if (tokenType === "url") {
    return resolveCoursewareServiceUrl(runtimeConfig, serviceId, pathSuffix);
  }

  if (tokenType === "address") {
    return resolveCoursewareServiceAddress(runtimeConfig, serviceId);
  }

  return null;
}

function replaceServiceTokens(
  root: HTMLElement,
  runtimeConfig: ResolvedCoursewareRuntimeConfig,
) {
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
    acceptNode(node) {
      if (!(node instanceof Text)) {
        return NodeFilter.FILTER_REJECT;
      }

      if (!node.nodeValue?.includes("{{service-")) {
        return NodeFilter.FILTER_REJECT;
      }

      const parent = node.parentElement;
      if (!parent) {
        return NodeFilter.FILTER_REJECT;
      }

      if (parent.closest("[data-widget-enhanced='true']")) {
        return NodeFilter.FILTER_REJECT;
      }

      return NodeFilter.FILTER_ACCEPT;
    },
  });

  const textNodes: Text[] = [];
  let currentNode = walker.nextNode();
  while (currentNode) {
    if (currentNode instanceof Text) {
      textNodes.push(currentNode);
    }
    currentNode = walker.nextNode();
  }

  for (const textNode of textNodes) {
    const parent = textNode.parentElement;
    const nodeValue = textNode.nodeValue;
    if (!parent || !nodeValue) {
      continue;
    }

    const allowLinks = !parent.closest("code, pre, a");
    const nextTextValue = nodeValue.replace(
      serviceTokenPattern,
      (
        fullMatch,
        tokenType: string,
        serviceId: string,
        pathSuffix?: string,
      ) => {
        const replacement = resolveServiceTokenValue(
          runtimeConfig,
          tokenType,
          serviceId,
          pathSuffix,
        );
        return replacement ?? fullMatch;
      },
    );

    if (!allowLinks) {
      if (nextTextValue !== nodeValue) {
        textNode.nodeValue = nextTextValue;
      }
      continue;
    }

    serviceTokenPattern.lastIndex = 0;
    let lastIndex = 0;
    let didReplace = false;
    const fragment = document.createDocumentFragment();
    let match = serviceTokenPattern.exec(nodeValue);

    while (match) {
      const [fullMatch, tokenType, serviceId, pathSuffix] = match;
      const replacement = resolveServiceTokenValue(
        runtimeConfig,
        tokenType,
        serviceId,
        pathSuffix,
      );

      if (replacement === null) {
        match = serviceTokenPattern.exec(nodeValue);
        continue;
      }

      didReplace = true;
      if (match.index > lastIndex) {
        fragment.append(nodeValue.slice(lastIndex, match.index));
      }

      if (tokenType === "url") {
        const link = document.createElement("a");
        const serviceLabel = serviceLabels[serviceId] ?? replacement;
        let visibleLabel = serviceLabel;

        try {
          const resolvedUrl = new URL(replacement);
          if (resolvedUrl.port) {
            visibleLabel = `${serviceLabel} on port ${resolvedUrl.port}`;
          }
        } catch {
          visibleLabel = serviceLabel;
        }

        link.className = "lab-service-pill";
        link.dataset.serviceId = serviceId;
        link.href = replacement;
        link.rel = "noreferrer";
        link.target = "_blank";
        link.title = replacement;
        link.textContent = visibleLabel;
        fragment.append(link);
      } else {
        fragment.append(replacement);
      }

      lastIndex = match.index + fullMatch.length;
      match = serviceTokenPattern.exec(nodeValue);
    }

    if (!didReplace) {
      continue;
    }

    if (lastIndex < nodeValue.length) {
      fragment.append(nodeValue.slice(lastIndex));
    }

    textNode.replaceWith(fragment);
  }
}

const LabContentArticle = memo(function LabContentArticle({
  className,
  html,
  onZoomImage,
}: LabContentArticleProps) {
  const containerRef = useRef<HTMLElement>(null);
  const [runtimeConfig, setRuntimeConfig] = useState(() =>
    normalizeCoursewareRuntimeConfig(),
  );
  const [isRuntimeResolved, setIsRuntimeResolved] = useState(false);

  const renderedContent = html
    .split(
      new RegExp(
        `(${escapeRegex(quantizationExplorerToken)}|${escapeRegex(quantizationGridExplorerToken)}|${escapeRegex(objective5ChatToken)}|${escapeRegex(lab8ChatToken)}|${escapeRegex(lab3TerminalToken)}|${escapeRegex(lab1ConfidenceToken)}|${escapeRegex(lab1NetronToken)}|${escapeRegex(tokenizerPlaygroundToken)})`,
        "g",
      ),
    )
    .filter(Boolean)
    .map((part, index) => {
      if (part === quantizationExplorerToken) {
        return <QuantizationExplorer key={`quantization-explorer-${index}`} />;
      }

      if (part === quantizationGridExplorerToken) {
        return (
          <QuantizationGridExplorer
            key={`quantization-grid-explorer-${index}`}
          />
        );
      }

      if (part === objective5ChatToken) {
        return <Objective5Chat key={`objective5-chat-${index}`} />;
      }

      if (part === lab8ChatToken) {
        return <Lab8Chat key={`lab8-chat-${index}`} />;
      }

      if (part === lab3TerminalToken) {
        return <Lab3TerminalFrame key={`lab3-terminal-${index}`} />;
      }

      if (part === lab1ConfidenceToken) {
        return <Lab1ConfidenceChat key={`lab1-confidence-${index}`} />;
      }

      if (part === lab1NetronToken) {
        return <Lab1NetronPanel key={`lab1-netron-${index}`} />;
      }

      if (part === tokenizerPlaygroundToken) {
        return (
          <TokenizerPlaygroundEmbed key={`tokenizer-playground-${index}`} />
        );
      }

      return (
        <Fragment key={`html-segment-${index}`}>
          <div dangerouslySetInnerHTML={{ __html: part }} />
        </Fragment>
      );
    });

  useEffect(() => {
    let isCancelled = false;

    void fetchCoursewareRuntimeConfig()
      .then((nextRuntimeConfig) => {
        if (isCancelled) return;
        setRuntimeConfig(nextRuntimeConfig);
      })
      .catch(() => {
        if (isCancelled) return;
        setRuntimeConfig(normalizeCoursewareRuntimeConfig());
      })
      .finally(() => {
        if (isCancelled) return;
        setIsRuntimeResolved(true);
      });

    return () => {
      isCancelled = true;
    };
  }, []);

  useEffect(() => {
    const root = containerRef.current;
    if (!root || !isRuntimeResolved) return;

    replaceServiceTokens(root, runtimeConfig);

    const preBlocks = root.querySelectorAll<HTMLPreElement>("pre");
    for (const pre of preBlocks) {
      const code = pre.querySelector<HTMLElement>("code");
      if (!code) continue;

      const blockText = code.textContent ?? "";
      if (looksLikeCliCommand(blockText, code.className)) {
        pre.classList.add("lab-cli-shell");
        ensureCopyButton(pre, "Copy");
        continue;
      }

      if (looksLikePromptTextBlock(blockText, code.className)) {
        pre.classList.add("lab-prompt-card");
        ensureCopyButton(pre, "Copy Text");
      }
    }

    enhanceSettingsLists(root);
    const cleanupHarnessSelectors = enhanceHarnessSelectors(root);

    const handleRootClick = (event: Event) => {
      const target = event.target as HTMLElement;
      const button = target.closest<HTMLButtonElement>(
        "button.lab-copy-button",
      );
      if (button) {
        const pre = button.closest("pre");
        const code = pre?.querySelector("code");
        const commandText = code?.textContent?.trimEnd();
        if (!commandText) return;
        const defaultLabel = button.dataset.defaultLabel ?? "Copy";

        void copyTextToClipboard(commandText)
          .then(() => {
            button.textContent = "Copied";
            button.classList.add("is-copied");
            window.setTimeout(() => {
              button.textContent = defaultLabel;
              button.classList.remove("is-copied");
            }, 1200);
          })
          .catch(() => {
            button.textContent = "Failed";
            window.setTimeout(() => {
              button.textContent = defaultLabel;
            }, 1200);
          });
        return;
      }

      const image = target.closest<HTMLImageElement>("img");
      if (!image || !root.contains(image)) return;

      const src = image.getAttribute("src");
      if (!src) return;

      event.preventDefault();
      event.stopPropagation();
      onZoomImage({
        src,
        alt: image.getAttribute("alt") ?? "",
      });
    };

    root.addEventListener("click", handleRootClick);
    return () => {
      cleanupHarnessSelectors();
      root.removeEventListener("click", handleRootClick);
    };
  }, [html, isRuntimeResolved, onZoomImage, runtimeConfig]);

  return (
    <article ref={containerRef} className={className}>
      {renderedContent}
    </article>
  );
});

export function LabContent({ className, html }: LabContentProps) {
  const [zoomedImage, setZoomedImage] = useState<ZoomedImageState | null>(null);
  const handleZoomImage = useCallback((image: ZoomedImageState) => {
    setZoomedImage(image);
  }, []);

  useEffect(() => {
    if (!zoomedImage) return;

    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";

    const activeElement = document.activeElement;
    const previousFocusedElement =
      activeElement instanceof HTMLElement ? activeElement : null;

    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setZoomedImage(null);
      }
    };

    window.addEventListener("keydown", handleEscape);
    return () => {
      window.removeEventListener("keydown", handleEscape);
      document.body.style.overflow = previousOverflow;
      previousFocusedElement?.focus();
    };
  }, [zoomedImage]);

  return (
    <>
      <LabContentArticle
        className={className}
        html={html}
        onZoomImage={handleZoomImage}
      />
      {zoomedImage ? (
        <div
          className="lab-image-modal"
          role="presentation"
          onClick={() => setZoomedImage(null)}
        >
          <div
            className="lab-image-modal__surface"
            onClick={(event) => event.stopPropagation()}
          >
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              className="lab-image-modal__image"
              src={zoomedImage.src}
              alt={zoomedImage.alt}
            />
          </div>
        </div>
      ) : null}
    </>
  );
}
