import fs from 'node:fs/promises';
import path from 'node:path';
import JSZip from 'jszip';
import { getCommentStyle, hasMarker } from '../src/lib/ai-marker';

type FileMap = Map<string, string>;

async function walkDir(dir: string, base = dir, out: FileMap = new Map()): Promise<FileMap> {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  for (const entry of entries) {
    const abs = path.join(dir, entry.name);
    if (entry.isDirectory()) {
      await walkDir(abs, base, out);
      continue;
    }
    const rel = path.relative(base, abs).replace(/\\/g, '/');
    const content = await fs.readFile(abs, 'utf8');
    out.set(rel, content);
  }
  return out;
}

async function readZip(zipPath: string): Promise<FileMap> {
  const buf = await fs.readFile(zipPath);
  const zip = await JSZip.loadAsync(buf);
  const out: FileMap = new Map();

  for (const [name, entry] of Object.entries(zip.files)) {
    if (entry.dir) continue;
    const content = await entry.async('string');
    out.set(name, content);
  }
  return out;
}

function validateFiles(files: FileMap): string[] {
  const errors: string[] = [];
  if (!files.has('SCRIBA_MANIFEST.json')) {
    errors.push('Missing SCRIBA_MANIFEST.json');
  }

  for (const [filePath, content] of files.entries()) {
    if (filePath === 'SCRIBA_MANIFEST.json') continue;
    if (filePath.endsWith('.scriba-marker.json')) {
      if (!hasMarker(content)) errors.push(`Invalid marker sidecar: ${filePath}`);
      continue;
    }

    const style = getCommentStyle(filePath);
    if (style === 'sidecar') {
      const sidecarPath = `${filePath}.scriba-marker.json`;
      if (!files.has(sidecarPath)) {
        errors.push(`Missing sidecar marker: ${sidecarPath}`);
      }
      continue;
    }

    if (!hasMarker(content)) {
      errors.push(`Missing marker header: ${filePath}`);
    }
  }

  return errors;
}

function parseArgValue(args: string[], key: string): string | undefined {
  const idx = args.findIndex((arg) => arg === key);
  if (idx < 0) return undefined;
  return args[idx + 1];
}

async function main() {
  const args = process.argv.slice(2);
  const target = parseArgValue(args, '--fixtures') ?? args[0];
  if (!target) {
    console.error('Usage: npx tsx scripts/validate-markers.ts --fixtures <zip-or-directory>');
    process.exit(1);
  }

  const abs = path.resolve(process.cwd(), target);
  const stat = await fs.stat(abs).catch(() => null);
  if (!stat) {
    console.error(`Path not found: ${abs}`);
    process.exit(1);
  }

  const files = stat.isDirectory() ? await walkDir(abs) : await readZip(abs);
  const failures = validateFiles(files);
  if (failures.length > 0) {
    console.error('Marker validation failed:');
    for (const fail of failures) console.error(`- ${fail}`);
    process.exit(1);
  }

  console.log(`Marker validation passed for ${target}`);
}

main().catch((error) => {
  console.error('Validation error:', error instanceof Error ? error.message : String(error));
  process.exit(1);
});
