import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { createRequire } from 'node:module';
import { c as chalk } from './chunks/index.js';
import 'node:process';
import 'node:os';
import 'node:tty';

/**
 * vite :: src/tailwind.mjs.
 *
 * Vite-based build/dev tooling for Vettvangur projects.
 *
 * These docs are generated from inline JSDoc in the repo and are intended for contributors.
 *
 * @generated
 * @module vite
 */

const /**
   * Pad.
   *
   * @param n - Value.
   * @param value - Value.
   * @returns Nothing.
   *
   * @generated
   * @example
   * // vite (src/tools/javascript/vite/src/tailwind.mjs)
   * // import { pad } from '@vettvangur/vite'
   *
   * pad(n, value)
   */
  pad = (n, w = 2) => String(n).padStart(w, '0');
const /**
   * Ts.
   *
   * @returns String result.
   *
   * @generated
   * @example
   * // vite (src/tools/javascript/vite/src/tailwind.mjs)
   * // import { ts } from '@vettvangur/vite'
   *
   * ts()
   */
  ts = () => {
    const d = new Date();
    return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${pad(d.getMilliseconds(), 3)}`
  };
const /**
   * Vite Tag.
   *
   * @generated
   * @example
   * console.log(viteTag)
   */
  viteTag = chalk.cyan('[styles]');
const /**
   * T.
   *
   * @returns Nothing.
   *
   * @generated
   * @example
   * // vite (src/tools/javascript/vite/src/tailwind.mjs)
   * // import { t } from '@vettvangur/vite'
   *
   * t()
   */
  t = () => chalk.dim(`[${ts()}]`);

/**
 * Tailwind plugin unified.
 *
 * @param options - Options object.
 * @param options.styles - Path to the styles directory.
 * @param options.cssEntries - Entry file list.
 * @param options.dest - Destination path.
 * @param options.watchContent - Extra content globs to watch.
 * @param options.razorDirs - Directory list.
 * @returns Result of the operation.
 * @throws When the operation fails.
 *
 * @example
 * // vite (src/tools/javascript/vite/src/tailwind.mjs)
 * // import { tailwindPluginUnified } from '@vettvangur/vite'
 *
 * tailwindPluginUnified({ styles: './src/styles', cssEntries: ['./src/styles/app.css'], dest: './dist', watchContent: ['./src/index.html'], razorDirs: ['./Views'] })
 */
function tailwindPluginUnified({
  styles, // absolute dir for CSS sources (config.styles.path)
  cssEntries, // entry CSS files (each imports "tailwindcss")
  dest, // absolute output dir
  watchContent = [], // extra globs to watch: wwwroot, etc.
  razorDirs = [], // dirs with .cshtml, e.g. [paths.views]
}) {
  if (typeof styles !== 'string' || !styles) {
    throw new Error(`[vettvangur-vite :: tailwind] "styles" must be a non-empty string.`)
  }
  if (!Array.isArray(cssEntries) || cssEntries.length === 0) {
    throw new Error(`[vettvangur-vite :: tailwind] "cssEntries" must be a non-empty string[].`)
  }
  if (typeof dest !== 'string' || !dest) {
    throw new Error(`[vettvangur-vite :: tailwind] "dest" must be a non-empty string.`)
  }

  const root = process.cwd();
  const existsDir = (p) => {
    try {
      return fs.existsSync(p) && fs.statSync(p).isDirectory()
    } catch {
      return false
    }
  };

  const entries = cssEntries.map((p) => (path.isAbsolute(p) ? p : path.resolve(root, p)));

  // ---------- resolver -------------------------------------------------------
  let cached;
  const stack = async () => {
    if (cached) {
      return cached
    }

    const esbuild = (await import('esbuild')).default;
    const appRequire = createRequire(path.join(process.cwd(), 'package.json'));
    const pkgRequire = createRequire(import.meta.url);

    async function tryImport(id, deepFallback) {
      try {
        return await import(id)
      } catch {}
      try {
        return await import(pathToFileURL(appRequire.resolve(deepFallback ?? id)).href)
      } catch {}
      try {
        return await import(pathToFileURL(pkgRequire.resolve(deepFallback ?? id)).href)
      } catch (e) {
        throw new Error(
          `[vettvangur-vite :: tailwind] Missing dependency "${id}". Install in your APP when styles.type:'tailwind':\n  pnpm add -D esbuild postcss @tailwindcss/postcss\n` +
            (deepFallback ? `Tried deep fallback: ${deepFallback}\n` : '') +
            `Original: ${e?.message || e}`
        )
      }
    }

    const postcssMod = await tryImport('postcss');
    const postcss = postcssMod.default ?? postcssMod;
    const twMod = await tryImport('@tailwindcss/postcss');
    const tailwindPostcss = twMod.default ?? twMod;

    cached = { esbuild, postcss, tailwindPostcss };
    return cached
  };

  // ---------- esbuild plugin: Tailwind via PostCSS ---------------------------
  function makeTailwindPostcssPlugin({ postcss, tailwindPostcss }) {
    return {
      name: 'tailwind-postcss',
      setup(build) {
        build.onLoad({ filter: /\.css$/i }, async (args) => {
          const src = await fs.promises.readFile(args.path, 'utf8');
          const result = await postcss([tailwindPostcss()]).process(src, {
            from: args.path,
            to: args.path,
            map: build.initialOptions.sourcemap ? { inline: true } : false,
          });
          return { contents: result.css, loader: 'css' }
        });
      },
    }
  }

  function baseEsbuildOptions({ outDir, sourcemap, plugin }) {
    return {
      entryPoints: entries,
      entryNames: '[name]',
      outExtension: { '.css': '.min.css' },
      bundle: true,
      sourcemap,
      minify: true,
      outdir: outDir,
      write: true,
      format: 'esm',
      splitting: false,
      target: 'es2017',
      logLevel: 'silent',
      loader: { '.css': 'css' },
      logOverride: {
        'empty-import-meta': 'silent',
        'equals-nan': 'silent',
        'this-is-undefined-in-esm': 'silent',
      },
      plugins: [plugin],
    }
  }

  let mode = 'serve';

  return {
    name: 'tailwind-postcss-unified',

    async configResolved(cfg) {
      mode = cfg.command;
      if (!existsDir(styles)) {
        this.error(`[vettvangur-vite :: tailwind] styles directory does not exist: ${styles}`);
      }
    },

    // ------------------------------ DEV --------------------------------------
    async configureServer(server) {
      if (mode !== 'serve') {
        return
      }

      const deps = await stack();
      const outDirDev = dest;
      fs.mkdirSync(outDirDev, { recursive: true });

      const plugin = makeTailwindPostcssPlugin(deps);
      const ctx = await deps.esbuild.context(baseEsbuildOptions({ outDir: outDirDev, sourcemap: true, plugin }));

      console.log(`${t()} ${viteTag} building styles...`);
      await ctx.rebuild();
      console.log(`${t()} ${viteTag} build complete`);

      await ctx.watch();

      // ----- WATCH GLOBS (Vite watcher) --------------------------------------
      const watchGlobs = new Set();

      // CSS source tree
      watchGlobs.add(path.join(styles, '**/*.css'));

      // Extra content globs from vite.config (if you care about html/js/css there)
      for (const raw of watchContent) {
        if (!raw) {
          continue
        }
        const abs = path.isAbsolute(raw) ? raw : path.resolve(root, raw);
        watchGlobs.add(abs);
      }

      const globs = Array.from(watchGlobs);
      if (globs.length) {
        server.watcher.add(globs);
      }

      let primed = false;
      server.watcher.once('ready', () => {
        primed = true;
      });
      setTimeout(() => {
        if (!primed) {
          primed = true;
        }
      }, 250);

      let pending = null;
      let inFlight = false;

      const schedule = () => {
        if (pending) {
          clearTimeout(pending);
        }
        pending = setTimeout(async () => {
          pending = null;
          if (inFlight) {
            return
          }
          inFlight = true;

          console.log(`${t()} ${viteTag} building styles (tailwind)...`);
          try {
            await ctx.rebuild();
          } catch (err) {
            console.error(err);
          }

          console.clear();
          console.log(`${t()} ${viteTag} reloaded`);
          server.ws.send({ type: 'full-reload' });

          inFlight = false;
        }, 80);
      };

      // chokidar-based watcher (CSS / anything Vite sees)
      server.watcher.on('all', (_evt, file) => {
        if (!primed || !file) {
          return
        }

        const f = file.toLowerCase();

        if (f.endsWith('.css') || f.endsWith('.html') || f.endsWith('.js')) {
          schedule();
        }
      });

      // ----- RAZOR FS.WATCH (direct on Views) --------------------------------
      const razorWatchers = [];

      const dirs = razorDirs.map((d) => (path.isAbsolute(d) ? d : path.resolve(root, d))).filter((d) => existsDir(d));

      for (const dir of dirs) {
        const w = fs.watch(dir, { recursive: true }, (_eventType, filename) => {
          if (!filename) {
            return
          }
          const lower = filename.toLowerCase();
          if (!lower.endsWith('.cshtml')) {
            return
          }

          const _full = path.join(dir, filename);
          schedule(); // this triggers ctx.rebuild() + full-reload
        });
        razorWatchers.push(w);
      }

      server.httpServer?.once('close', async () => {
        for (const w of razorWatchers) {
          try {
            w.close();
          } catch {}
        }
        await ctx.dispose();
      });
    },

    // ------------------------------ BUILD ------------------------------------
    async buildStart() {
      if (mode !== 'build') {
        return
      }

      const deps = await stack();
      fs.mkdirSync(dest, { recursive: true });

      const plugin = makeTailwindPostcssPlugin(deps);
      await deps.esbuild.build(baseEsbuildOptions({ outDir: dest, sourcemap: true, plugin }));
    },
  }
}

export { tailwindPluginUnified };
//# sourceMappingURL=tailwind.js.map
