import { defineComponent, getCurrentInstance, onErrorCaptured, shallowRef, useId } from "vue";
import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from "vue/server-renderer";
import { isPromise } from "@vue/shared";
import { useState } from "../composables/state.js";
import { createBuffer } from "./utils.js";
const VALID_TAG_RE = /^[a-z][a-z0-9-]*$/i;
function sanitizeTag(tag, fallback) {
  return VALID_TAG_RE.test(tag) ? tag : fallback;
}
const NuxtClientFallbackServer = defineComponent({
  name: "NuxtClientFallback",
  inheritAttrs: false,
  props: {
    fallbackTag: {
      type: String,
      default: () => "div"
    },
    fallback: {
      type: String,
      default: () => ""
    },
    placeholder: {
      type: String
    },
    placeholderTag: {
      type: String
    },
    keepFallback: {
      type: Boolean,
      default: () => false
    }
  },
  emits: {
    "ssr-error"(_error) {
      return true;
    }
  },
  async setup(_, ctx) {
    const vm = getCurrentInstance();
    const ssrFailed = shallowRef(false);
    const error = useState(useId());
    onErrorCaptured((err) => {
      error.value = true;
      ssrFailed.value = true;
      ctx.emit("ssr-error", err);
      return false;
    });
    try {
      const defaultSlot = ctx.slots.default?.();
      const ssrVNodes = createBuffer();
      if (defaultSlot) {
        for (let i = 0; i < defaultSlot.length; i++) {
          ssrRenderVNode(ssrVNodes.push, defaultSlot[i], vm);
        }
      }
      const buffer = ssrVNodes.getBuffer();
      if (buffer.hasAsync) {
        await Promise.all(buffer.flat(Infinity).filter(isPromise));
      }
      return { ssrFailed, ssrVNodes };
    } catch (ssrError) {
      error.value = true;
      ctx.emit("ssr-error", ssrError);
      return { ssrFailed: true, ssrVNodes: [] };
    }
  },
  ssrRender(ctx, push, parent) {
    if (ctx.ssrFailed) {
      const { fallback, placeholder } = ctx.$slots;
      if (fallback || placeholder) {
        ssrRenderSlot(ctx.$slots, fallback ? "fallback" : "placeholder", {}, null, push, parent);
      } else {
        const content = ctx.placeholder || ctx.fallback;
        const tag = sanitizeTag(ctx.placeholderTag || ctx.fallbackTag, "div");
        push(`<${tag}${ssrRenderAttrs(ctx.$attrs)}>${content}</${tag}>`);
      }
    } else {
      push("<!--[-->");
      push(ctx.ssrVNodes.getBuffer());
      push("<!--]-->");
    }
  }
});
export default NuxtClientFallbackServer;
