import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
import { bnToEn, normalize } from "./translations-dict";

export type Lang = "bn" | "en";

type Dict = Record<string, { bn: string; en: string }>;

const dict: Dict = {
  // Sidebar groups
  "g.main": { bn: "মূল", en: "Main" },
  "g.inventory": { bn: "ইনভেন্টরি", en: "Inventory" },
  "g.transactions": { bn: "লেনদেন", en: "Transactions" },
  "g.party": { bn: "পার্টি", en: "Parties" },
  "g.reports": { bn: "রিপোর্ট", en: "Reports" },
  "g.settings": { bn: "সেটিংস", en: "Settings" },
  // Sidebar items
  "n.dashboard": { bn: "ড্যাশবোর্ড", en: "Dashboard" },
  "n.pos": { bn: "POS / বিলিং", en: "POS / Billing" },
  "n.products": { bn: "প্রোডাক্ট", en: "Products" },
  "n.stock": { bn: "স্টক", en: "Stock" },
  "n.barcode": { bn: "বারকোড / SKU", en: "Barcode / SKU" },
  "n.warranty": { bn: "ওয়ারেন্টি / সিরিয়াল", en: "Warranty / Serial" },
  "n.sales": { bn: "বিক্রয়", en: "Sales" },
  "n.purchases": { bn: "ক্রয়", en: "Purchases" },
  "n.invoices": { bn: "ইনভয়েস", en: "Invoices" },
  "n.dues": { bn: "ডিউ / পেমেন্ট", en: "Dues / Payments" },
  "n.installments": { bn: "কিস্তি (EMI)", en: "Installments (EMI)" },
  "n.expenses": { bn: "খরচ", en: "Expenses" },
  "n.loans": { bn: "ধার দিলাম / ধার নিলাম", en: "Loans (Given / Taken)" },
  "n.cash": { bn: "ক্যাশ ও ব্যাংক", en: "Cash & Bank" },
  "n.customers": { bn: "কাস্টমার", en: "Customers" },
  "n.suppliers": { bn: "সাপ্লায়ার", en: "Suppliers" },
  "n.attendance": { bn: "স্টাফ হাজিরা", en: "Staff Attendance" },
  "n.employees": { bn: "কর্মী", en: "Employees" },
  "n.pl": { bn: "লাভ-লোকসান", en: "Profit & Loss" },
  "n.reports": { bn: "রিপোর্ট", en: "Reports" },
  "n.settings": { bn: "সেটিংস", en: "Settings" },
  // Topbar
  "tb.settings": { bn: "সেটিংস", en: "Settings" },
  "tb.logout": { bn: "লগআউট", en: "Logout" },
  "tb.toggle": { bn: "EN", en: "বাং" },
};

type Ctx = {
  lang: Lang;
  setLang: (l: Lang) => void;
  toggle: () => void;
  t: (k: keyof typeof dict | string) => string;
};

const LanguageContext = createContext<Ctx | null>(null);

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

function translateText(s: string): string | null {
  if (!s) return null;
  const norm = normalize(s);
  if (!norm) return null;
  const hit = bnToEn[norm];
  if (hit !== undefined) return hit;
  // Try whole text with trailing punctuation stripped
  const stripped = norm.replace(/[।:।?!.,…]+$/, "");
  if (stripped !== norm && bnToEn[stripped] !== undefined) {
    const suffix = norm.slice(stripped.length);
    return bnToEn[stripped] + suffix;
  }
  return null;
}

function translateDOM(root: Node) {
  // Text nodes
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
    acceptNode(n) {
      const v = n.nodeValue;
      if (!v || !/[\u0980-\u09FF]/.test(v)) return NodeFilter.FILTER_REJECT;
      // Skip script/style
      const p = n.parentElement;
      if (!p) return NodeFilter.FILTER_REJECT;
      const tag = p.tagName;
      if (tag === "SCRIPT" || tag === "STYLE") return NodeFilter.FILTER_REJECT;
      return NodeFilter.FILTER_ACCEPT;
    },
  });
  const nodes: Text[] = [];
  let cur: Node | null;
  while ((cur = walker.nextNode())) nodes.push(cur as Text);
  for (const tn of nodes) {
    const orig = tn.nodeValue || "";
    const trimmedLead = orig.match(/^\s*/)?.[0] ?? "";
    const trimmedTail = orig.match(/\s*$/)?.[0] ?? "";
    const core = orig.slice(trimmedLead.length, orig.length - trimmedTail.length);
    const tr = translateText(core);
    if (tr !== null && tr !== core) {
      // Stash original for restore on toggle back
      const p = tn.parentElement;
      if (p && !p.dataset.bnOrig) p.dataset.bnOrig = "1";
      (tn as any).__bnOrig = orig;
      tn.nodeValue = trimmedLead + tr + trimmedTail;
    }
  }
  // Attributes
  if (root instanceof Element || root === document.body) {
    const scope: ParentNode = root instanceof Element ? root : document.body;
    const selector = ATTRS.map((a) => `[${a}]`).join(",");
    const els = (scope as ParentNode).querySelectorAll(selector);
    els.forEach((el) => {
      for (const a of ATTRS) {
        const v = el.getAttribute(a);
        if (!v || !/[\u0980-\u09FF]/.test(v)) continue;
        const tr = translateText(v);
        if (tr !== null && tr !== v) {
          if (!el.getAttribute(`data-bn-${a}`)) el.setAttribute(`data-bn-${a}`, v);
          el.setAttribute(a, tr);
        }
      }
    });
  }
}

function restoreDOM(root: Node) {
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
  let cur: Node | null;
  while ((cur = walker.nextNode())) {
    const orig = (cur as any).__bnOrig as string | undefined;
    if (orig !== undefined) {
      (cur as Text).nodeValue = orig;
      delete (cur as any).__bnOrig;
    }
  }
  if (root instanceof Element || root === document.body) {
    const scope: ParentNode = root instanceof Element ? root : document.body;
    ATTRS.forEach((a) => {
      scope.querySelectorAll(`[data-bn-${a}]`).forEach((el) => {
        const orig = el.getAttribute(`data-bn-${a}`);
        if (orig !== null) {
          el.setAttribute(a, orig);
          el.removeAttribute(`data-bn-${a}`);
        }
      });
    });
  }
}

let observer: MutationObserver | null = null;
let rafId: number | null = null;
const pending = new Set<Node>();

function scheduleTranslate(node: Node) {
  pending.add(node);
  if (rafId !== null) return;
  rafId = requestAnimationFrame(() => {
    rafId = null;
    const nodes = Array.from(pending);
    pending.clear();
    for (const n of nodes) {
      if (n.isConnected) translateDOM(n);
    }
  });
}

function startObserver() {
  if (observer || typeof window === "undefined") return;
  observer = new MutationObserver((muts) => {
    for (const m of muts) {
      if (m.type === "childList") {
        m.addedNodes.forEach((n) => {
          if (n.nodeType === 1 || n.nodeType === 3) scheduleTranslate(n);
        });
      } else if (m.type === "characterData") {
        if (m.target.parentNode) scheduleTranslate(m.target);
      } else if (m.type === "attributes") {
        if (m.target instanceof Element) scheduleTranslate(m.target);
      }
    }
  });
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    characterData: true,
    attributes: true,
    attributeFilter: ATTRS,
  });
}

function stopObserver() {
  if (observer) {
    observer.disconnect();
    observer = null;
  }
  if (rafId !== null) {
    cancelAnimationFrame(rafId);
    rafId = null;
  }
  pending.clear();
}

export function LanguageProvider({ children }: { children: ReactNode }) {
  const [lang, setLangState] = useState<Lang>("bn");

  useEffect(() => {
    const stored = (typeof window !== "undefined" && (localStorage.getItem("lang") as Lang)) || "bn";
    setLangState(stored);
    if (typeof document !== "undefined") document.documentElement.lang = stored;
  }, []);

  useEffect(() => {
    if (typeof document === "undefined") return;
    if (lang === "en") {
      translateDOM(document.body);
      startObserver();
    } else {
      stopObserver();
      restoreDOM(document.body);
    }
    return () => {
      stopObserver();
    };
  }, [lang]);

  const setLang = (l: Lang) => {
    setLangState(l);
    if (typeof window !== "undefined") localStorage.setItem("lang", l);
    if (typeof document !== "undefined") document.documentElement.lang = l;
  };

  const toggle = () => setLang(lang === "bn" ? "en" : "bn");
  const t = (k: string) => dict[k]?.[lang] ?? k;

  return <LanguageContext.Provider value={{ lang, setLang, toggle, t }}>{children}</LanguageContext.Provider>;
}

export function useLang() {
  const ctx = useContext(LanguageContext);
  if (!ctx) throw new Error("useLang must be used inside LanguageProvider");
  return ctx;
}
