import { URI as N } from "../../../../../vscode-uri@3.0.8/node_modules/vscode-uri/lib/esm/index.js";
import { isReference as x, isAstNode as g } from "../syntax-tree.js";
import { getDocument as p } from "../utils/ast-utils.js";
import { findNodesForProperty as D } from "../utils/grammar-utils.js";
function b(a) {
  return typeof a.$comment == "string";
}
function R(a) {
  return typeof a == "object" && !!a && ("$ref" in a || "$error" in a);
}
class I {
  constructor(t) {
    this.ignoreProperties = /* @__PURE__ */ new Set(["$container", "$containerProperty", "$containerIndex", "$document", "$cstNode"]), this.langiumDocuments = t.shared.workspace.LangiumDocuments, this.astNodeLocator = t.workspace.AstNodeLocator, this.nameProvider = t.references.NameProvider, this.commentProvider = t.documentation.CommentProvider;
  }
  serialize(t, e) {
    const i = e ?? {}, n = e == null ? void 0 : e.replacer, d = (c, r) => this.replacer(c, r, i), s = n ? (c, r) => n(c, r, d) : d;
    try {
      return this.currentDocument = p(t), JSON.stringify(t, s, e == null ? void 0 : e.space);
    } finally {
      this.currentDocument = void 0;
    }
  }
  deserialize(t, e) {
    const i = e ?? {}, n = JSON.parse(t);
    return this.linkNode(n, n, i), n;
  }
  replacer(t, e, { refText: i, sourceText: n, textRegions: d, comments: s, uriConverter: c }) {
    var r, f, l, u;
    if (!this.ignoreProperties.has(t))
      if (x(e)) {
        const o = e.ref, m = i ? e.$refText : void 0;
        if (o) {
          const h = p(o);
          let $ = "";
          this.currentDocument && this.currentDocument !== h && (c ? $ = c(h.uri, e) : $ = h.uri.toString());
          const v = this.astNodeLocator.getAstNodePath(o);
          return {
            $ref: `${$}#${v}`,
            $refText: m
          };
        } else
          return {
            $error: (f = (r = e.error) === null || r === void 0 ? void 0 : r.message) !== null && f !== void 0 ? f : "Could not resolve reference",
            $refText: m
          };
      } else if (g(e)) {
        let o;
        if (d && (o = this.addAstNodeRegionWithAssignmentsTo(Object.assign({}, e)), (!t || e.$document) && (o != null && o.$textRegion) && (o.$textRegion.documentURI = (l = this.currentDocument) === null || l === void 0 ? void 0 : l.uri.toString())), n && !t && (o ?? (o = Object.assign({}, e)), o.$sourceText = (u = e.$cstNode) === null || u === void 0 ? void 0 : u.text), s) {
          o ?? (o = Object.assign({}, e));
          const m = this.commentProvider.getComment(e);
          m && (o.$comment = m.replace(/\r/g, ""));
        }
        return o ?? e;
      } else
        return e;
  }
  addAstNodeRegionWithAssignmentsTo(t) {
    const e = (i) => ({
      offset: i.offset,
      end: i.end,
      length: i.length,
      range: i.range
    });
    if (t.$cstNode) {
      const i = t.$textRegion = e(t.$cstNode), n = i.assignments = {};
      return Object.keys(t).filter((d) => !d.startsWith("$")).forEach((d) => {
        const s = D(t.$cstNode, d).map(e);
        s.length !== 0 && (n[d] = s);
      }), t;
    }
  }
  linkNode(t, e, i, n, d, s) {
    for (const [r, f] of Object.entries(t))
      if (Array.isArray(f))
        for (let l = 0; l < f.length; l++) {
          const u = f[l];
          R(u) ? f[l] = this.reviveReference(t, r, e, u, i) : g(u) && this.linkNode(u, e, i, t, r, l);
        }
      else R(f) ? t[r] = this.reviveReference(t, r, e, f, i) : g(f) && this.linkNode(f, e, i, t, r);
    const c = t;
    c.$container = n, c.$containerProperty = d, c.$containerIndex = s;
  }
  reviveReference(t, e, i, n, d) {
    let s = n.$refText, c = n.$error;
    if (n.$ref) {
      const r = this.getRefNode(i, n.$ref, d.uriConverter);
      if (g(r))
        return s || (s = this.nameProvider.getName(r)), {
          $refText: s ?? "",
          ref: r
        };
      c = r;
    }
    if (c) {
      const r = {
        $refText: s ?? ""
      };
      return r.error = {
        container: t,
        property: e,
        message: c,
        reference: r
      }, r;
    } else
      return;
  }
  getRefNode(t, e, i) {
    try {
      const n = e.indexOf("#");
      if (n === 0) {
        const r = this.astNodeLocator.getAstNode(t, e.substring(1));
        return r || "Could not resolve path: " + e;
      }
      if (n < 0) {
        const r = i ? i(e) : N.parse(e), f = this.langiumDocuments.getDocument(r);
        return f ? f.parseResult.value : "Could not find document for URI: " + e;
      }
      const d = i ? i(e.substring(0, n)) : N.parse(e.substring(0, n)), s = this.langiumDocuments.getDocument(d);
      if (!s)
        return "Could not find document for URI: " + e;
      if (n === e.length - 1)
        return s.parseResult.value;
      const c = this.astNodeLocator.getAstNode(s.parseResult.value, e.substring(n + 1));
      return c || "Could not resolve URI: " + e;
    } catch (n) {
      return String(n);
    }
  }
}
export {
  I as DefaultJsonSerializer,
  b as isAstNodeWithComment
};
