import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { useLanguage } from "@/context/LanguageContext";

/**
 * DOM-level English → Arabic auto-translator.
 *
 * Many legacy page components render raw English strings directly in JSX
 * without going through the `t()` / `tr()` translation helpers. Rewriting
 * every component would be a large change, so we take a second pass at
 * the rendered DOM after React commits: we walk visible text nodes and
 * replace any node whose trimmed content exactly matches a known English
 * string with its Arabic equivalent.
 *
 * Why this is safe:
 *   - We only touch `Text` nodes (never attributes, elements, or code).
 *   - We only replace when `lang === "ar"` — English stays untouched.
 *   - We skip nodes inside `<script>`, `<style>`, `<code>`, `<pre>`,
 *     `<input>`, `<textarea>`, `.keep-ltr`, `.no-translate`, and nodes
 *     whose parent has `data-no-translate`.
 *   - We match on the TRIMMED text so surrounding whitespace is
 *     preserved. Translations that aren't in the catalog are simply
 *     left in English — we never invent a translation.
 *   - We also translate a small set of attribute values (`placeholder`,
 *     `title`, `aria-label`, `alt`, `value` on submit/button inputs).
 *   - A MutationObserver re-runs the sweep whenever new nodes appear
 *     (e.g. after navigation, lazy data load, or state updates).
 *
 * The dictionary is exposed on `window.__DOITEASY_EN_TO_AR__` by
 * LanguageContext; it is populated once at module load from the same
 * catalog used by `t()` / `tr()`.
 */

const SKIP_TAGS = new Set([
  "SCRIPT",
  "STYLE",
  "CODE",
  "PRE",
  "TEXTAREA",
  "INPUT",
  "NOSCRIPT",
  "SVG",
  "PATH",
]);

const ATTR_TRANSLATABLE = ["placeholder", "title", "aria-label", "alt"];

function isSkippable(node: Node): boolean {
  let p: Node | null = node.parentNode;
  while (p) {
    if (p.nodeType === Node.ELEMENT_NODE) {
      const el = p as HTMLElement;
      if (SKIP_TAGS.has(el.tagName)) return true;
      if (el.classList && (el.classList.contains("keep-ltr") || el.classList.contains("no-translate"))) {
        return true;
      }
      if (el.hasAttribute && el.hasAttribute("data-no-translate")) return true;
      if (el.hasAttribute && el.hasAttribute("contenteditable")) return true;
    }
    p = p.parentNode;
  }
  return false;
}

function translateTextNode(
  node: Text,
  dict: Record<string, string>,
): boolean {
  const raw = node.nodeValue ?? "";
  const trimmed = raw.trim();
  if (!trimmed) return false;
  // Skip pure numeric / currency / price-like strings; they're already LTR-safe.
  if (/^[\d.,\s$€£¥%+\-/:]+$/.test(trimmed)) return false;
  const translated = dict[trimmed];
  if (!translated || translated === trimmed) return false;
  // Preserve any leading/trailing whitespace so inline layouts don't collapse.
  const leading = raw.match(/^\s*/)?.[0] ?? "";
  const trailing = raw.match(/\s*$/)?.[0] ?? "";
  node.nodeValue = `${leading}${translated}${trailing}`;
  // Mark ancestor element so we can skip it on the next sweep.
  const el = node.parentElement;
  if (el) el.setAttribute("data-i18n-ar", "1");
  return true;
}

function translateAttributes(
  el: Element,
  dict: Record<string, string>,
): void {
  for (const attr of ATTR_TRANSLATABLE) {
    const v = el.getAttribute(attr);
    if (!v) continue;
    const trimmed = v.trim();
    if (!trimmed) continue;
    const translated = dict[trimmed];
    if (translated && translated !== trimmed) {
      el.setAttribute(attr, translated);
      el.setAttribute(`data-i18n-${attr}`, "1");
    }
  }
  // submit/button inputs carry visible text in `value`
  if (el.tagName === "INPUT") {
    const t = (el as HTMLInputElement).type;
    if (t === "submit" || t === "button" || t === "reset") {
      const v = (el as HTMLInputElement).value;
      if (v) {
        const trimmed = v.trim();
        const translated = dict[trimmed];
        if (translated && translated !== trimmed) {
          (el as HTMLInputElement).value = translated;
        }
      }
    }
  }
}

function sweep(root: Node, dict: Record<string, string>): void {
  if (!root) return;
  // Translate text nodes via TreeWalker.
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
    acceptNode(node) {
      if (isSkippable(node)) return NodeFilter.FILTER_REJECT;
      return NodeFilter.FILTER_ACCEPT;
    },
  });
  const textNodes: Text[] = [];
  let n = walker.nextNode();
  while (n) {
    textNodes.push(n as Text);
    n = walker.nextNode();
  }
  for (const node of textNodes) {
    translateTextNode(node, dict);
  }

  // Translate translatable attributes on elements.
  if (root.nodeType === Node.ELEMENT_NODE) {
    const elRoot = root as Element;
    translateAttributes(elRoot, dict);
    const all = elRoot.querySelectorAll("*");
    for (const el of Array.from(all)) {
      if (SKIP_TAGS.has(el.tagName)) continue;
      translateAttributes(el, dict);
    }
  } else if (root.nodeType === Node.DOCUMENT_NODE || root === document) {
    const all = document.querySelectorAll("body *");
    for (const el of Array.from(all)) {
      if (SKIP_TAGS.has(el.tagName)) continue;
      translateAttributes(el, dict);
    }
  }
}

/**
 * Mount once inside `SiteLayout`. It listens to language/route changes
 * and runs a translation sweep plus a MutationObserver for async content.
 */
export default function AutoTranslate() {
  const { lang } = useLanguage();
  const { pathname } = useLocation();

  useEffect(() => {
    if (typeof window === "undefined" || typeof document === "undefined") return;
    if (lang !== "ar") return;
    const dict = (window as any).__DOITEASY_EN_TO_AR__ as
      | Record<string, string>
      | undefined;
    if (!dict) return;

    // Initial + follow-up sweeps give React / data loads a chance to paint.
    const runSweep = () => sweep(document.body, dict);
    const raf = requestAnimationFrame(runSweep);
    const t1 = window.setTimeout(runSweep, 120);
    const t2 = window.setTimeout(runSweep, 400);
    const t3 = window.setTimeout(runSweep, 1200);

    // Observe DOM for async content (SPA route swaps, product loads, etc.).
    const observer = new MutationObserver((mutations) => {
      for (const m of mutations) {
        if (m.type === "childList") {
          m.addedNodes.forEach((node) => {
            if (node.nodeType === Node.TEXT_NODE) {
              if (!isSkippable(node)) translateTextNode(node as Text, dict);
            } else if (node.nodeType === Node.ELEMENT_NODE) {
              sweep(node, dict);
            }
          });
        } else if (m.type === "characterData" && m.target.nodeType === Node.TEXT_NODE) {
          if (!isSkippable(m.target)) translateTextNode(m.target as Text, dict);
        }
      }
    });
    observer.observe(document.body, {
      childList: true,
      subtree: true,
      characterData: true,
    });

    return () => {
      cancelAnimationFrame(raf);
      window.clearTimeout(t1);
      window.clearTimeout(t2);
      window.clearTimeout(t3);
      observer.disconnect();
    };
  }, [lang, pathname]);

  return null;
}