import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { doctorCommand } from './doctor.js';

const here = dirname(fileURLToPath(import.meta.url));
const TEMPLATES_DIR = join(here, '..', '..', 'templates');

export interface InitOptions {
  name?: string;
  template?: string;
  prekeyServer?: string;
  cwd?: string;
  runDoctor?: boolean;
}

export async function initCommand(opts: InitOptions = {}): Promise<void> {
  const name = opts.name ?? 'my-shade-app';
  const template = opts.template ?? 'bun-server';
  const cwd = opts.cwd ?? process.cwd();
  const target = join(cwd, name);

  if (existsSync(target)) {
    throw new Error(`Target directory "${target}" already exists`);
  }

  const templateDir = join(TEMPLATES_DIR, template);
  if (!existsSync(templateDir)) {
    const available = listTemplates();
    throw new Error(
      `Template "${template}" not found. Available: ${available.join(', ')}`,
    );
  }

  // Recursive copy with placeholder substitution
  mkdirSync(target, { recursive: true });
  copyRecursive(templateDir, target, {
    __PROJECT_NAME__: name,
    __PREKEY_SERVER__: opts.prekeyServer ?? 'http://localhost:3900',
  });

  console.log(`✓ Created ${name} from template "${template}"`);
  console.log('');
  console.log(`  cd ${name}`);
  console.log('  bun install');
  console.log('  bun run start');

  if (opts.runDoctor) {
    console.log('');
    await doctorCommand({ cwd: target });
  }
}

export function listTemplates(): string[] {
  if (!existsSync(TEMPLATES_DIR)) return [];
  return readdirSync(TEMPLATES_DIR).filter((name) => {
    return statSync(join(TEMPLATES_DIR, name)).isDirectory();
  });
}

function copyRecursive(
  source: string,
  dest: string,
  replacements: Record<string, string>,
): void {
  mkdirSync(dest, { recursive: true });
  for (const entry of readdirSync(source)) {
    const srcPath = join(source, entry);
    const destPath = join(dest, entry);
    const st = statSync(srcPath);

    if (st.isDirectory()) {
      copyRecursive(srcPath, destPath, replacements);
    } else {
      const content = readFileSync(srcPath, 'utf-8');
      const substituted = Object.entries(replacements).reduce(
        (acc, [key, value]) => acc.replaceAll(key, value),
        content,
      );
      writeFileSync(destPath, substituted);
    }
  }
}
