import { invariant, isNonEmptyArray } from "@likec4/core";
import { filter, flatMap, isNonNullish, isTruthy, mapToObj, pipe } from "remeda";
import stripIndent from "strip-indent";
import { ast } from "../../ast.js";
import { getFqnElementRef } from "../../utils/elementRef.js";
import { checksFromDiagnostics } from "../../validation/index.js";
export function toSingleLine(str) {
  return isNonNullish(str) ? removeIndent(str).split("\n").join(" ") : void 0;
}
export function removeIndent(str) {
  return isNonNullish(str) ? stripIndent(str).trim() : void 0;
}
export class BaseParser {
  constructor(services, doc) {
    this.services = services;
    this.doc = doc;
    this.isValid = checksFromDiagnostics(doc).isValid;
  }
  isValid;
  resolveFqn(node) {
    if (ast.isDeploymentElement(node)) {
      return this.services.likec4.DeploymentsIndex.getFqn(node);
    }
    if (ast.isExtendElement(node)) {
      return getFqnElementRef(node.element);
    }
    const fqn = this.services.likec4.FqnIndex.getFqn(node);
    invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
    return fqn;
  }
  getAstNodePath(node) {
    return this.services.workspace.AstNodeLocator.getAstNodePath(node);
  }
  getMetadata(metadataAstNode) {
    if (!metadataAstNode || !this.isValid(metadataAstNode)) {
      return void 0;
    }
    return mapToObj(metadataAstNode.props, (p) => [p.key, removeIndent(p.value)]);
  }
  convertTags(withTags) {
    return this.parseTags(withTags);
  }
  parseTags(withTags) {
    let iter = withTags?.tags;
    if (!iter) {
      return null;
    }
    const tags = [];
    while (iter) {
      try {
        if (this.isValid(iter)) {
          const values = iter.values.map((t) => t.ref?.name).filter(isTruthy);
          if (values.length > 0) {
            tags.push(...values);
          }
        }
      } catch (e) {
      }
      iter = iter.prev;
    }
    tags.reverse();
    return isNonEmptyArray(tags) ? tags : null;
  }
  convertLinks(source) {
    return this.parseLinks(source);
  }
  parseLinks(source) {
    if (!source?.props || source.props.length === 0) {
      return void 0;
    }
    return pipe(
      source.props,
      filter(ast.isLinkProperty),
      flatMap((p) => {
        if (!this.isValid(p)) {
          return [];
        }
        const url = p.value;
        if (isTruthy(url)) {
          const title = isTruthy(p.title) ? toSingleLine(p.title) : void 0;
          return title ? { url, title } : { url };
        }
        return [];
      })
    );
  }
}
