import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import path from 'node:path';
import { ensureHtmlThumbnail } from './mindspace-thumbnails.mjs';

export function workspaceThumbnailRelativePath(htmlRelativePath) {
  const normalized = String(htmlRelativePath ?? '').replace(/^\/+/, '');
  const dir = path.posix.dirname(normalized);
  const base = path.basename(normalized, path.extname(normalized));
  const thumb = `${base}.thumbnail.svg`;
  return dir === '.' ? thumb : path.posix.join(dir, thumb);
}

export function workspaceThumbnailAbsolutePath(publishDir, htmlRelativePath) {
  return path.join(publishDir, workspaceThumbnailRelativePath(htmlRelativePath));
}

export async function ensureWorkspaceHtmlThumbnail(publishDir, htmlRelativePath, html, meta = {}) {
  const htmlPath = path.join(publishDir, htmlRelativePath);
  const content = html ?? (await fsPromises.readFile(htmlPath, 'utf8'));
  const thumbRel = workspaceThumbnailRelativePath(htmlRelativePath);
  return ensureHtmlThumbnail(publishDir, thumbRel, content, {
    ...meta,
    contentBaseDir: path.dirname(htmlPath),
  });
}

export async function readWorkspaceThumbnailIfExists(publishDir, htmlRelativePath) {
  try {
    return await fsPromises.readFile(workspaceThumbnailAbsolutePath(publishDir, htmlRelativePath), 'utf8');
  } catch {
    return null;
  }
}

async function scanPublishTree(publishRoot) {
  if (!fs.existsSync(publishRoot)) return;
  const entries = await fsPromises.readdir(publishRoot, { withFileTypes: true });
  for (const entry of entries) {
    if (!entry.isDirectory() || entry.name === 'wiki' || entry.name.startsWith('.')) continue;
    const userDir = path.join(publishRoot, entry.name);
    await scanUserHtmlFiles(userDir);
  }
}

async function scanUserHtmlFiles(userDir) {
  const walk = async (dir) => {
    const entries = await fsPromises.readdir(dir, { withFileTypes: true });
    for (const entry of entries) {
      const full = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        if (entry.name === '.agents' || entry.name === 'node_modules') continue;
        await walk(full);
        continue;
      }
      if (!entry.name.endsWith('.html') || entry.name.endsWith('.thumbnail.svg')) continue;
      const rel = path.relative(userDir, full);
      await ensureWorkspaceHtmlThumbnail(userDir, rel).catch(() => {});
    }
  };
  await walk(userDir);
}

export function startWorkspaceThumbnailWatcher(publishRoot) {
  if (!fs.existsSync(publishRoot)) {
    fs.mkdirSync(publishRoot, { recursive: true });
  }

  void scanPublishTree(publishRoot);

  const pending = new Map();
  const schedule = (userDir, relativePath) => {
    const key = path.join(userDir, relativePath);
    const existing = pending.get(key);
    if (existing) clearTimeout(existing);
    pending.set(
      key,
      setTimeout(() => {
        pending.delete(key);
        void ensureWorkspaceHtmlThumbnail(userDir, relativePath).catch(() => {});
      }, 400),
    );
  };

  const attachUserWatcher = (userDir) => {
    if (!fs.existsSync(userDir)) return;
    void scanUserHtmlFiles(userDir);
    try {
      fs.watch(userDir, { recursive: true }, (_event, filename) => {
        if (!filename || !String(filename).endsWith('.html')) return;
        if (String(filename).endsWith('.thumbnail.svg')) return;
        schedule(userDir, filename);
      });
    } catch {
      // Some platforms disallow recursive watch; startup scan still runs.
    }
  };

  for (const entry of fs.readdirSync(publishRoot, { withFileTypes: true })) {
    if (entry.isDirectory() && entry.name !== 'wiki' && !entry.name.startsWith('.')) {
      attachUserWatcher(path.join(publishRoot, entry.name));
    }
  }

  try {
    fs.watch(publishRoot, (_event, filename) => {
      if (!filename) return;
      const userDir = path.join(publishRoot, filename);
      if (fs.existsSync(userDir) && fs.statSync(userDir).isDirectory()) {
        attachUserWatcher(userDir);
      }
    });
  } catch {
    // ignore
  }
}
