/*!
 * BlockWriteAI Code Assist Plugin
 * Adds Prettier-powered formatting and lightweight code suggestions to BlockWriteAI code blocks.
 */
(function (global) {
  "use strict";

  var BlockWriteAI = global.BlockWriteAI;
  if (!BlockWriteAI || BlockWriteAI.__codeAssistPluginInstalled) return;
  BlockWriteAI.__codeAssistPluginInstalled = true;

  var options = {
    prettier: true,
    suggestions: true,
    prettierVersion: "3.8.1",
    tabWidth: 2,
    prettierBase: "",
    extraSuggestions: {}
  };

  var prettierPromise = null;
  var originalRenderCode = BlockWriteAI.prototype.renderCode;
  var originalFormatCodeBlock = BlockWriteAI.prototype.formatCodeBlock;

  var FORMATTERS = {
    javascript: "babel",
    typescript: "typescript",
    json: "json",
    html: "html",
    css: "css",
    markdown: "markdown"
  };

  var SUPPORTED_LANGUAGES = [
    "plaintext",
    "javascript",
    "typescript",
    "html",
    "css",
    "json",
    "php",
    "python",
    "java",
    "csharp",
    "cpp",
    "sql",
    "bash",
    "markdown"
  ];

  var SNIPPETS = {
    javascript: [
      { label: "function", detail: "Function declaration", insert: "function name() {\n  $0\n}" },
      { label: "const", detail: "Constant", insert: "const name = $0;" },
      { label: "let", detail: "Variable", insert: "let name = $0;" },
      { label: "if", detail: "If statement", insert: "if ($0) {\n  \n}" },
      { label: "for", detail: "For loop", insert: "for (let i = 0; i < length; i += 1) {\n  $0\n}" },
      { label: "map", detail: "Array map", insert: "array.map(function (item) {\n  return $0;\n});" },
      { label: "async", detail: "Async function", insert: "async function name() {\n  $0\n}" },
      { label: "try", detail: "Try catch", insert: "try {\n  $0\n} catch (error) {\n  console.error(error);\n}" },
      { label: "console", detail: "Console log", insert: "console.log($0);" }
    ],
    typescript: [
      { label: "interface", detail: "Interface", insert: "interface Name {\n  $0\n}" },
      { label: "type", detail: "Type alias", insert: "type Name = $0;" },
      { label: "const", detail: "Constant", insert: "const name: Type = $0;" },
      { label: "function", detail: "Typed function", insert: "function name(): void {\n  $0\n}" },
      { label: "async", detail: "Async function", insert: "async function name(): Promise<void> {\n  $0\n}" }
    ],
    html: [
      { label: "!DOCTYPE", detail: "HTML document type", insert: "<!DOCTYPE html>" },
      { label: "html", detail: "HTML page", insert: "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>$0</title>\n</head>\n<body>\n  \n</body>\n</html>" },
      { label: "div", detail: "Division", insert: "<div>\n  $0\n</div>" },
      { label: "section", detail: "Section", insert: "<section>\n  $0\n</section>" },
      { label: "article", detail: "Article", insert: "<article>\n  $0\n</article>" },
      { label: "button", detail: "Button", insert: '<button type="button">$0</button>' },
      { label: "a", detail: "Link", insert: '<a href="#">$0</a>' },
      { label: "img", detail: "Image", insert: '<img src="$0" alt="">' },
      { label: "ul", detail: "List", insert: "<ul>\n  <li>$0</li>\n</ul>" },
      { label: "table", detail: "Table", insert: "<table>\n  <tr>\n    <td>$0</td>\n  </tr>\n</table>" }
    ],
    css: [
      { label: "display", detail: "Display", insert: "display: $0;" },
      { label: "grid", detail: "Grid layout", insert: "display: grid;\ngap: $0;" },
      { label: "flex", detail: "Flex layout", insert: "display: flex;\nalign-items: center;\ngap: $0;" },
      { label: "color", detail: "Text color", insert: "color: $0;" },
      { label: "background", detail: "Background", insert: "background: $0;" },
      { label: "border", detail: "Border", insert: "border: 1px solid $0;" },
      { label: "radius", detail: "Border radius", insert: "border-radius: $0;" },
      { label: "media", detail: "Media query", insert: "@media (max-width: 768px) {\n  $0\n}" }
    ],
    php: [
      { label: "function", detail: "Function", insert: "function name() {\n    $0\n}" },
      { label: "if", detail: "If statement", insert: "if ($0) {\n    \n}" },
      { label: "foreach", detail: "Foreach loop", insert: "foreach ($items as $item) {\n    $0\n}" },
      { label: "echo", detail: "Echo", insert: "echo $0;" }
    ],
    python: [
      { label: "def", detail: "Function", insert: "def name():\n    $0" },
      { label: "class", detail: "Class", insert: "class Name:\n    def __init__(self):\n        $0" },
      { label: "if", detail: "If statement", insert: "if $0:\n    " },
      { label: "for", detail: "For loop", insert: "for item in items:\n    $0" },
      { label: "try", detail: "Try except", insert: "try:\n    $0\nexcept Exception as error:\n    print(error)" }
    ],
    sql: [
      { label: "select", detail: "Select query", insert: "SELECT $0\nFROM table_name;" },
      { label: "insert", detail: "Insert query", insert: "INSERT INTO table_name (column)\nVALUES ($0);" },
      { label: "update", detail: "Update query", insert: "UPDATE table_name\nSET column = $0\nWHERE condition;" },
      { label: "join", detail: "Join", insert: "JOIN table_name ON $0" }
    ],
    bash: [
      { label: "if", detail: "If statement", insert: "if [ $0 ]; then\n  \nfi" },
      { label: "for", detail: "For loop", insert: "for item in \"$@\"; do\n  $0\ndone" },
      { label: "echo", detail: "Echo", insert: "echo \"$0\"" }
    ],
    java: [
      { label: "class", detail: "Class", insert: "public class Name {\n  public static void main(String[] args) {\n    $0\n  }\n}" },
      { label: "main", detail: "Main method", insert: "public static void main(String[] args) {\n  $0\n}" },
      { label: "sout", detail: "Print line", insert: "System.out.println($0);" },
      { label: "if", detail: "If statement", insert: "if ($0) {\n  \n}" },
      { label: "for", detail: "For loop", insert: "for (int i = 0; i < count; i++) {\n  $0\n}" }
    ],
    csharp: [
      { label: "class", detail: "Class", insert: "public class Name\n{\n    $0\n}" },
      { label: "main", detail: "Main method", insert: "public static void Main(string[] args)\n{\n    $0\n}" },
      { label: "cw", detail: "Console write line", insert: "Console.WriteLine($0);" },
      { label: "if", detail: "If statement", insert: "if ($0)\n{\n    \n}" },
      { label: "foreach", detail: "Foreach loop", insert: "foreach (var item in items)\n{\n    $0\n}" }
    ],
    cpp: [
      { label: "include", detail: "Include header", insert: "#include <$0>" },
      { label: "main", detail: "Main function", insert: "int main() {\n  $0\n  return 0;\n}" },
      { label: "cout", detail: "Output stream", insert: "std::cout << $0 << std::endl;" },
      { label: "if", detail: "If statement", insert: "if ($0) {\n  \n}" },
      { label: "for", detail: "For loop", insert: "for (int i = 0; i < count; i++) {\n  $0\n}" }
    ],
    json: [
      { label: "object", detail: "JSON object", insert: "{\n  \"$0\": \"\"\n}" },
      { label: "array", detail: "JSON array", insert: "[\n  $0\n]" },
      { label: "string", detail: "String property", insert: "\"name\": \"$0\"" },
      { label: "number", detail: "Number property", insert: "\"count\": $0" },
      { label: "boolean", detail: "Boolean property", insert: "\"enabled\": true" }
    ],
    markdown: [
      { label: "heading", detail: "Heading", insert: "## $0" },
      { label: "link", detail: "Link", insert: "[$0](https://example.com)" },
      { label: "image", detail: "Image", insert: "![$0](image-url)" },
      { label: "code", detail: "Code fence", insert: "```language\n$0\n```" },
      { label: "table", detail: "Table", insert: "| Header | Header |\n| --- | --- |\n| $0 |  |" }
    ],
    plaintext: [
      { label: "note", detail: "Simple note", insert: "Note: $0" },
      { label: "todo", detail: "Task line", insert: "TODO: $0" },
      { label: "summary", detail: "Summary heading", insert: "Summary\n$0" }
    ]
  };

  var KEYWORDS = {
    javascript: "await break case catch class const continue default delete do else export extends finally for function if import in instanceof let new return static switch this throw try typeof var void while yield true false null undefined console document window",
    typescript: "abstract any as async await boolean class const constructor declare enum export extends false from function implements import interface keyof let namespace never null number private protected public readonly return static string super true type undefined unknown void",
    html: "a abbr address article aside audio b base blockquote body br button canvas caption cite code col colgroup data datalist dd del details div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hr html iframe img input label legend li link main meta nav ol option p picture pre progress script section select small source span strong style summary table tbody td template textarea tfoot th thead time title tr ul video",
    css: "align-items background background-color border border-radius box-shadow color display flex flex-direction font-size font-weight gap grid grid-template-columns height justify-content line-height margin max-width min-height object-fit opacity overflow padding position text-align transform transition width z-index",
    json: "true false null",
    php: "array as class echo else elseif extends false foreach function if implements interface namespace new null private protected public return static switch true try use var while",
    python: "and as assert async await break class continue def del elif else except false finally for from global if import in is lambda none nonlocal not or pass raise return true try while with yield print self",
    java: "abstract boolean break byte case catch char class const continue default double else enum extends false final finally float for if implements import int interface long new null package private protected public return static string super switch this throw throws true try void while",
    csharp: "abstract as async await bool break case catch class const continue decimal default delegate do double else enum event false finally float for foreach if in int interface internal is lock namespace new null object override private protected public readonly return sealed static string switch this throw true try using var virtual void while",
    cpp: "auto bool break case catch char class const continue default delete do double else enum false float for if include int long namespace new nullptr private protected public return sizeof static std string struct switch template this throw true try typename using void while",
    sql: "SELECT FROM WHERE JOIN LEFT RIGHT INNER OUTER INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP GROUP BY ORDER HAVING LIMIT OFFSET DISTINCT COUNT SUM AVG MIN MAX",
    bash: "case cd chmod cp do done echo elif else esac export fi for function grep if in mkdir mv read rm sed then while",
    markdown: "heading link image code table quote list todo bold italic"
  };

  function escapeHTML(value) {
    return String(value == null ? "" : value)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function injectStyles() {
    if (document.querySelector("style[data-blockwriteai-code-assist]")) return;
    var style = document.createElement("style");
    style.dataset.blockwriteaiCodeAssist = "true";
    style.textContent =
      ".rbe-code-wrap{position:relative;}" +
      ".rbe-code-assist-status{margin-left:auto;font-size:12px;font-weight:740;color:inherit;opacity:.8;}" +
      ".rbe-code-assist-status.is-error{color:#b91c1c;}" +
      ".rbe-code-assist-panel{position:absolute;z-index:12;width:min(280px,calc(100% - 24px));max-height:210px;overflow:auto;border:1px solid var(--rbe-border,#d7dee8);border-radius:8px;background:#fff;box-shadow:0 16px 40px rgba(15,23,42,.16);padding:4px;}" +
      ".rbe-code-assist-panel[hidden]{display:none;}" +
      ".rbe-code-assist-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;width:100%;border:0;border-radius:6px;background:transparent;color:#172033;padding:7px 8px;text-align:left;font:13px/1.3 Arial,sans-serif;cursor:pointer;}" +
      ".rbe-code-assist-item strong{font-family:\"SFMono-Regular\",Consolas,\"Liberation Mono\",monospace;font-size:13px;}" +
      ".rbe-code-assist-item small{color:#667085;}" +
      ".rbe-code-assist-item.is-active,.rbe-code-assist-item:hover{background:#e7efff;color:#143f91;}" +
      ".rbe-code-assist-hint{grid-column:1/-1;color:#667085;font-size:11px;padding:3px 8px 5px;}";
    document.head.appendChild(style);
  }

  function codeLanguage(block) {
    var select = block && block.querySelector(".rbe-code-language");
    return select ? select.value || "plaintext" : "plaintext";
  }

  function localVendorAsset(path) {
    var scriptSrc = "";
    if (typeof document !== "undefined") {
      scriptSrc = document.currentScript && document.currentScript.src || "";
      if (!scriptSrc) {
        var scripts = document.getElementsByTagName ? document.getElementsByTagName("script") : [];
        for (var i = scripts.length - 1; i >= 0; i -= 1) {
          var src = scripts[i].src || "";
          if (/blockwriteai-code-assist(?:\.min)?\.js(?:\?|#|$)/.test(src)) {
            scriptSrc = src;
            break;
          }
        }
      }
    }
    var prefix = /\/plugins\/blockwriteai-code-assist(?:\.min)?\.js(?:\?|#|$)/.test(scriptSrc) ? "../" : "";
    try {
      return scriptSrc ? new URL(prefix + path, scriptSrc).href : path;
    } catch (error) {
      return prefix + path;
    }
  }

  function scriptUrl(path) {
    return options.prettierBase ? options.prettierBase + path : localVendorAsset("vendor/prettier/" + path);
  }

  function loadPrettier() {
    if (!options.prettier) return Promise.reject(new Error("Prettier is disabled"));
    if (prettierPromise) return prettierPromise;
    prettierPromise = Promise.all([
      import(scriptUrl("standalone.mjs")),
      import(scriptUrl("plugins/babel.mjs")),
      import(scriptUrl("plugins/estree.mjs")),
      import(scriptUrl("plugins/typescript.mjs")),
      import(scriptUrl("plugins/html.mjs")),
      import(scriptUrl("plugins/postcss.mjs")),
      import(scriptUrl("plugins/markdown.mjs"))
    ]).then(function (modules) {
      return {
        prettier: modules[0],
        plugins: modules.slice(1).map(function (module) { return module.default || module; })
      };
    });
    return prettierPromise;
  }

  function setStatus(wrap, text, isError) {
    var status = wrap && wrap.querySelector(".rbe-code-assist-status");
    if (!status) return;
    status.textContent = text || "";
    status.classList.toggle("is-error", !!isError);
    if (text) {
      clearTimeout(status._rbeTimer);
      status._rbeTimer = setTimeout(function () {
        status.textContent = "";
        status.classList.remove("is-error");
      }, isError ? 3600 : 1800);
    }
  }

  function prettierParser(language) {
    return FORMATTERS[language] || "";
  }

  function languageIsSupported(language, select) {
    if (!language) return false;
    if (select) {
      return Array.prototype.some.call(select.options || [], function (option) {
        return option.value === language;
      });
    }
    return SUPPORTED_LANGUAGES.indexOf(language) !== -1;
  }

  function languageLabel(language, select) {
    if (select) {
      var option = Array.prototype.find.call(select.options || [], function (item) {
        return item.value === language;
      });
      if (option) return option.textContent || language;
    }
    return String(language || "Plain text").replace(/^\w/, function (letter) { return letter.toUpperCase(); });
  }

  function detectLanguage(code) {
    var raw = String(code || "");
    var text = raw.trim();
    if (!text) return "";
    var lower = text.toLowerCase();

    if (/^<\?php\b/i.test(text) || /\$\w+\s*=/.test(text) || /\b(echo|namespace|use)\s+[\w\\]+;/.test(text)) return "php";
    if (/^(<!|<\/?html\b|<\/?head\b|<\/?body\b|<\/?(div|section|article|span|button|table|form|input|script|style|img|a)\b)/i.test(text) || /<\/[a-z][\w:-]*>\s*$/i.test(text)) return "html";
    if (/^\s*[{[]/.test(raw) && (/"[^"]+"\s*:/.test(raw) || /^[\s{\["\]},:0-9.truefalsnul-]+$/i.test(raw))) return "json";
    if (/^#{1,6}\s/.test(text) || /^```/.test(text) || /^\s*[-*]\s+\[[ x]\]/i.test(text) || /\[[^\]]+\]\([^)]+\)/.test(text)) return "markdown";
    if (/^#include\b/.test(text) || /\bstd::\w+/.test(text) || /\bcout\s*<</.test(text) || /\bint\s+main\s*\(/.test(text)) return "cpp";
    if (/\busing\s+System\s*;/.test(text) || /\bConsole\.Write(Line)?\s*\(/.test(text) || /\bnamespace\s+\w+/.test(text)) return "csharp";
    if (/\bpublic\s+(class|static)\b/.test(text) || /\bSystem\.out\.println\s*\(/.test(text) || /\bpackage\s+[\w.]+;/.test(text)) return "java";
    if (/\binterface\s+\w+/.test(text) || /\btype\s+\w+\s*=/.test(text) || /:\s*(string|number|boolean|unknown|any)\b/.test(text)) return "typescript";
    if (/\b(const|let|var)\s+\w+\s*=/.test(text) || /\bfunction\s+\w*\s*\(/.test(text) || /=>/.test(text) || /\b(console|document|window)\./.test(text) || /\b(import|export)\s+/.test(text)) return "javascript";
    if (/^\s*(def|class)\s+\w+/.test(text) || /\bprint\s*\(/.test(text) || /\bfrom\s+\w+\s+import\b/.test(text) || /\bimport\s+\w+/.test(text) || /:\s*(#.*)?$/.test(text)) return "python";
    if (/\b(SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|ALTER\s+TABLE|DROP\s+TABLE)\b/i.test(text)) return "sql";
    if (/^#!/.test(text) || /\b(echo|chmod|sudo|grep|sed)\b/.test(text) || /^\s*(if|for|while)\s+.*;\s*do\b/.test(text)) return "bash";
    if (/@media\b/.test(text) || /[#.][\w-]+\s*\{/.test(text) || /\b[a-z-]+\s*:\s*[^;{}]+;/.test(text)) return "css";
    return "";
  }

  function keywordSuggestions(language) {
    return String(KEYWORDS[language] || "")
      .split(/\s+/)
      .filter(Boolean)
      .map(function (keyword) {
        return { label: keyword, detail: "Keyword", insert: keyword };
      });
  }

  function mergeSuggestions(list) {
    var seen = Object.create(null);
    return list.filter(function (item) {
      var key = (item.label || "") + "\u0000" + (item.insert || item.label || "");
      if (!item.label || seen[key]) return false;
      seen[key] = true;
      return true;
    });
  }

  function formatWithPrettier(code, language) {
    var parser = prettierParser(language);
    if (!parser) return Promise.reject(new Error("Prettier parser is not available for " + language));
    return loadPrettier().then(function (bundle) {
      return bundle.prettier.format(code, {
        parser: parser,
        plugins: bundle.plugins,
        tabWidth: options.tabWidth,
        printWidth: 100,
        semi: true,
        singleQuote: language === "javascript" || language === "typescript",
        bracketSameLine: false
      });
      });
  }

  function codeHasRegexLiteral(code) {
    return /(^|[=(:,\[\{!&|?;]\s*)\/(?![/*])(?:\\.|[^\/\n])+\/[dgimsuvy]*/.test(String(code || ""));
  }

  function currentToken(textarea, language) {
    var pos = textarea.selectionStart || 0;
    var before = textarea.value.slice(0, pos);
    if (language === "html") {
      var declarationMatch = before.match(/<!([\w-]*)$/i);
      if (declarationMatch) {
        return { text: "!" + (declarationMatch[1] || ""), start: pos - declarationMatch[0].length, end: pos, trigger: "html-declaration", force: true };
      }
      var htmlMatch = before.match(/<\/?([\w:-]*)$/);
      if (htmlMatch) {
        return { text: htmlMatch[1] || "", start: pos - htmlMatch[0].length, end: pos, trigger: "html-tag", force: true };
      }
    }
    if (language === "css") {
      var cssMatch = before.match(/(?:^|[;{]\s*)([a-z-]*)$/i);
      if (cssMatch) return { text: cssMatch[1] || "", start: pos - (cssMatch[1] || "").length, end: pos, trigger: "css-property", force: !cssMatch[1] };
    }
    if (language === "json") {
      var jsonMatch = before.match(/(?:^|[{,]\s*)"?([\w-]*)$/);
      if (jsonMatch) return { text: jsonMatch[1] || "", start: pos - (jsonMatch[1] || "").length, end: pos, trigger: "json-key", force: !jsonMatch[1] };
    }
    var match = before.match(/[A-Za-z_$][\w$-]*$/);
    return match ? { text: match[0], start: pos - match[0].length, end: pos } : { text: "", start: pos, end: pos };
  }

  function suggestionsFor(language, token, forced) {
    token = typeof token === "string" ? { text: token } : token || { text: "" };
    var list = [];
    if (language === "plaintext") {
      Object.keys(SNIPPETS).forEach(function (key) {
        if (key !== "plaintext") list = list.concat(SNIPPETS[key] || [], keywordSuggestions(key));
      });
      list = list.concat(SNIPPETS.plaintext || [], keywordSuggestions("plaintext"));
    } else {
      list = (SNIPPETS[language] || []).concat(keywordSuggestions(language), options.extraSuggestions[language] || []);
    }
    if (token.trigger === "html-declaration") {
      list = [
        { label: "!DOCTYPE", detail: "HTML document type", insert: "<!DOCTYPE html>" },
        { label: "!--", detail: "HTML comment", insert: "<!-- $0 -->" }
      ].concat(list);
    }
    if (!list.length) list = SNIPPETS.plaintext.concat(keywordSuggestions("plaintext"));
    list = mergeSuggestions(list);
    var lower = (token.text || "").toLowerCase();
    return list
      .filter(function (item) {
        return forced || !lower || item.label.toLowerCase().indexOf(lower) === 0;
      })
      .slice(0, 9);
  }

  function caretPosition(textarea, editor) {
    var style = getComputedStyle(textarea);
    var lineHeight = parseFloat(style.lineHeight) || 19;
    var paddingLeft = parseFloat(style.paddingLeft) || 12;
    var paddingTop = parseFloat(style.paddingTop) || 12;
    var measure = document.createElement("span");
    measure.style.cssText = "position:absolute;visibility:hidden;font:" + style.font + ";white-space:pre;";
    measure.textContent = "mmmmmmmmmm";
    document.body.appendChild(measure);
    var charWidth = measure.getBoundingClientRect().width / 10 || 8;
    measure.remove();
    var before = textarea.value.slice(0, textarea.selectionStart || 0).split("\n");
    var row = before.length - 1;
    var col = before[before.length - 1].length;
    return {
      left: Math.max(8, Math.min(editor.clientWidth - 288, paddingLeft + col * charWidth - textarea.scrollLeft)),
      top: Math.max(8, Math.min(editor.clientHeight - 220, paddingTop + (row + 1) * lineHeight - textarea.scrollTop))
    };
  }

  function insertSuggestion(textarea, token, suggestion) {
    var insert = suggestion.insert || suggestion.label;
    var marker = insert.indexOf("$0");
    var clean = insert.replace("$0", "");
    var value = textarea.value;
    textarea.value = value.slice(0, token.start) + clean + value.slice(token.end);
    var caret = token.start + (marker >= 0 ? marker : clean.length);
    textarea.focus();
    textarea.setSelectionRange(caret, caret);
    textarea.dispatchEvent(new Event("input", { bubbles: true }));
  }

  function enhanceSuggestions(instance, wrap) {
    if (!options.suggestions || !wrap || wrap.dataset.codeAssistEnhanced === "true") return;
    wrap.dataset.codeAssistEnhanced = "true";
    var textarea = wrap.querySelector(".rbe-code-input");
    var editor = wrap.querySelector(".rbe-code-editor");
    var header = wrap.querySelector(".rbe-code-header");
    var languageSelect = wrap.querySelector(".rbe-code-language");
    if (!textarea || !editor || !header) return;

    if (!header.querySelector(".rbe-code-assist-status")) {
      header.appendChild(document.createElement("span")).className = "rbe-code-assist-status";
    }

    var panel = document.createElement("div");
    panel.className = "rbe-code-assist-panel";
    panel.hidden = true;
    editor.appendChild(panel);
    var activeIndex = 0;
    var activeToken = null;
    var activeSuggestions = [];
    var autoChangingLanguage = false;

    if (languageSelect) {
      languageSelect.addEventListener("change", function () {
        if (autoChangingLanguage) return;
        languageSelect.dataset.codeAssistUserLanguage = "true";
        languageSelect.dataset.codeAssistAutoLanguage = "";
      });
    }

    function hide() {
      panel.hidden = true;
      activeSuggestions = [];
    }

    function applyDetectedLanguage() {
      if (!languageSelect) return codeLanguage(wrap.closest(".rbe-block"));
      var detected = detectLanguage(textarea.value);
      var current = languageSelect.value || "plaintext";
      if (!detected && languageSelect.dataset.codeAssistAutoLanguage === "true" && current !== "plaintext") {
        autoChangingLanguage = true;
        languageSelect.value = "plaintext";
        try {
          if (global.jQuery && global.jQuery.fn && global.jQuery.fn.select2) {
            global.jQuery(languageSelect).val("plaintext").trigger("change.select2");
          }
        } catch (ignore) {}
        languageSelect.dispatchEvent(new Event("change", { bubbles: true }));
        autoChangingLanguage = false;
        languageSelect.dataset.codeAssistAutoLanguage = "";
        return "plaintext";
      }
      if (!detected || !languageIsSupported(detected, languageSelect)) return current;
      if (languageSelect.dataset.codeAssistUserLanguage === "true" && current !== "plaintext") return current;
      if (current !== "plaintext" && languageSelect.dataset.codeAssistAutoLanguage !== "true" && current !== detected) return current;
      if (current === detected) {
        languageSelect.dataset.codeAssistAutoLanguage = "true";
        return current;
      }
      autoChangingLanguage = true;
      languageSelect.value = detected;
      languageSelect.dataset.codeAssistAutoLanguage = "true";
      try {
        if (global.jQuery && global.jQuery.fn && global.jQuery.fn.select2) {
          global.jQuery(languageSelect).val(detected).trigger("change.select2");
        }
      } catch (ignore) {}
      languageSelect.dispatchEvent(new Event("change", { bubbles: true }));
      autoChangingLanguage = false;
      setStatus(wrap, "Detected " + languageLabel(detected, languageSelect));
      return detected;
    }

    function render(items) {
      panel.innerHTML =
        items
          .map(function (item, index) {
            return '<button type="button" class="rbe-code-assist-item' + (index === activeIndex ? " is-active" : "") + '" data-index="' + index + '"><strong>' + escapeHTML(item.label) + "</strong><small>" + escapeHTML(item.detail || "") + "</small></button>";
          })
          .join("") +
        '<div class="rbe-code-assist-hint">Tab/Enter to insert, Ctrl+Space for all suggestions</div>';
    }

    function show(forced) {
      var language = applyDetectedLanguage();
      activeToken = currentToken(textarea, language);
      activeSuggestions = suggestionsFor(language, activeToken, forced);
      if (!activeSuggestions.length || (!forced && activeToken.text.length < 1 && !activeToken.force)) {
        hide();
        return;
      }
      activeIndex = Math.min(activeIndex, activeSuggestions.length - 1);
      render(activeSuggestions);
      var pos = caretPosition(textarea, editor);
      panel.style.left = pos.left + "px";
      panel.style.top = pos.top + "px";
      panel.hidden = false;
    }

    textarea.addEventListener("keydown", function (event) {
      if ((event.ctrlKey || event.metaKey) && event.code === "Space") {
        event.preventDefault();
        show(true);
        return;
      }
      if (event.altKey && event.shiftKey && event.key.toLowerCase() === "f") {
        event.preventDefault();
        instance.formatCodeBlock(wrap.closest(".rbe-block"));
        return;
      }
      if (panel.hidden) return;
      if (event.key === "ArrowDown") {
        event.preventDefault();
        activeIndex = (activeIndex + 1) % activeSuggestions.length;
        render(activeSuggestions);
      } else if (event.key === "ArrowUp") {
        event.preventDefault();
        activeIndex = (activeIndex - 1 + activeSuggestions.length) % activeSuggestions.length;
        render(activeSuggestions);
      } else if (event.key === "Enter" || event.key === "Tab") {
        event.preventDefault();
        insertSuggestion(textarea, activeToken, activeSuggestions[activeIndex]);
        hide();
      } else if (event.key === "Escape") {
        event.preventDefault();
        hide();
      }
    });

    textarea.addEventListener("input", function () {
      activeIndex = 0;
      setTimeout(function () { show(false); }, 0);
    });
    textarea.addEventListener("scroll", hide);
    textarea.addEventListener("blur", function () {
      setTimeout(hide, 180);
    });
    panel.addEventListener("mousedown", function (event) {
      var button = event.target.closest(".rbe-code-assist-item");
      if (!button) return;
      event.preventDefault();
      var suggestion = activeSuggestions[Number(button.dataset.index || 0)];
      if (suggestion) insertSuggestion(textarea, activeToken || currentToken(textarea, codeLanguage(wrap.closest(".rbe-block"))), suggestion);
      hide();
    });
  }

  BlockWriteAI.prototype.renderCode = function (body, data) {
    originalRenderCode.call(this, body, data);
    injectStyles();
    var wrap = body.querySelector(".rbe-code-wrap");
    if (wrap) enhanceSuggestions(this, wrap);
  };

  BlockWriteAI.prototype.formatCodeBlock = function (block) {
    if (!block || block.dataset.type !== "code") return;
    var wrap = block.querySelector(".rbe-code-wrap");
    var textarea = block.querySelector(".rbe-code-input");
    var language = codeLanguage(block);
    if (!textarea) return;
    if (!prettierParser(language)) {
      originalFormatCodeBlock.call(this, block);
      return;
    }
    var instance = this;
    var button = block.querySelector(".rbe-code-format");
    if (button) button.disabled = true;
    setStatus(wrap, "Formatting...");
    formatWithPrettier(textarea.value, language)
      .then(function (formatted) {
        textarea.value = String(formatted || "").replace(/\n+$/g, "");
        instance.refreshCodeBlock(block);
        instance.changed(true);
        setStatus(wrap, "Formatted");
      })
      .catch(function () {
        if ((language === "javascript" || language === "typescript") && codeHasRegexLiteral(textarea.value)) {
          instance.refreshCodeBlock(block);
          instance.changed(true);
          setStatus(wrap, "Prettier unavailable, code preserved", true);
          return;
        }
        originalFormatCodeBlock.call(instance, block);
        setStatus(wrap, "Formatted", false);
      })
      .finally(function () {
        if (button) button.disabled = false;
      });
  };

  global.BlockWriteAICodeAssist = {
    configure: function (nextOptions) {
      options = Object.assign({}, options, nextOptions || {});
      options.extraSuggestions = Object.assign({}, options.extraSuggestions || {});
      prettierPromise = null;
    },
    formatWithPrettier: formatWithPrettier,
    enhanceAll: function (root) {
      injectStyles();
      Array.prototype.slice.call((root || document).querySelectorAll(".rbe-code-wrap")).forEach(function (wrap) {
        var instance = global.editor || null;
        enhanceSuggestions(instance || { formatCodeBlock: function () {} }, wrap);
      });
    }
  };
})(typeof window !== "undefined" ? window : this);
