import { existsSync, mkdtempSync, rmSync, writeFileSync, mkdirSync, readFileSync, symlinkSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { spawnSync } from "node:child_process";

const root = new URL("..", import.meta.url).pathname;
const workdir = mkdtempSync(join(tmpdir(), "gnexus-ui-kit-vue-pack-"));
const appdir = join(workdir, "consumer");
const npmCache = join(workdir, "npm-cache");
const exampleNodeModules = join(root, "examples/vue/node_modules");
const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));

if (!existsSync(join(exampleNodeModules, "vue")) || !existsSync(join(exampleNodeModules, "vite"))) {
  throw new Error("Run npm --prefix examples/vue install before npm run test:vue-package");
}

function run(command, args, options = {}) {
  const result = spawnSync(command, args, {
    cwd: options.cwd || root,
    env: {
      ...process.env,
      npm_config_cache: npmCache
    },
    stdio: "inherit",
    shell: false
  });

  if (result.status !== 0) {
    throw new Error(`${command} ${args.join(" ")} failed`);
  }
}

function writeConsumerApp(tarball) {
  mkdirSync(join(appdir, "src"), { recursive: true });
  mkdirSync(join(appdir, "node_modules/gnexus-ui-kit"), { recursive: true });

  writeFileSync(
    join(appdir, "package.json"),
    `${JSON.stringify(
      {
        private: true,
        type: "module",
        scripts: {
          build: "vite build"
        },
        dependencies: {
          "gnexus-ui-kit": `file:${tarball}`,
          vue: "^3.5.22"
        },
        devDependencies: {}
      },
      null,
      2
    )}\n`
  );

  writeFileSync(
    join(appdir, "index.html"),
    `<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GNexus Vue Package Smoke</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
`
  );

  writeFileSync(
    join(appdir, "src/main.js"),
    `import { createApp, ref } from "vue";
import "gnexus-ui-kit/dist/css/kit.css";
import "gnexus-ui-kit/dist/assets/fonts/phosphor-icons/src/css/icons.css";
import { GnButton, GnInput, GnModal, GnTabs, GnToastProvider, useToast } from "gnexus-ui-kit/vue";

const SmokeScreen = {
  components: { GnButton, GnInput, GnModal, GnTabs },
  setup() {
    const open = ref(false);
    const name = ref("GNexus");
    const tab = ref("one");
    const toast = useToast();
    const tabs = [
      { id: "one", label: "One" },
      { id: "two", label: "Two" }
    ];

    function showToast() {
      toast.success({ title: "Ready", text: name.value });
    }

    return { open, name, tab, tabs, showToast };
  },
  template: \`
    <main class="container py-4">
      <GnInput v-model="name" label="Name" />
      <GnTabs v-model="tab" :items="tabs">
        <template #one>First tab</template>
        <template #two>Second tab</template>
      </GnTabs>
      <GnButton variant="accent" icon="ph-sparkle" @click="showToast">Toast</GnButton>
      <GnButton variant="secondary" @click="open = true">Modal</GnButton>
      <GnModal v-model:open="open" title="Pack smoke">
        Imported from tarball.
      </GnModal>
    </main>
  \`
};

createApp({
  components: { GnToastProvider, SmokeScreen },
  template: \`
    <GnToastProvider>
      <SmokeScreen />
    </GnToastProvider>
  \`
}).mount("#app");
`
  );
}

function installPackedKit(tarball) {
  run("tar", ["-xzf", tarball, "--strip-components=1", "-C", join(appdir, "node_modules/gnexus-ui-kit")]);
  symlinkSync(join(exampleNodeModules, "vue"), join(appdir, "node_modules/vue"), "dir");
}

try {
  run("npm", ["run", "build"]);
  run("npm", ["pack", "--pack-destination", workdir]);

  const tarball = join(workdir, `gnexus-ui-kit-${packageJson.version}.tgz`);
  writeConsumerApp(tarball);
  installPackedKit(tarball);

  run("node", [join(exampleNodeModules, "vite/bin/vite.js"), "build"], { cwd: appdir });
} finally {
  rmSync(workdir, { recursive: true, force: true });
}
