import path from 'path'
import { spawn } from 'child_process'
import { promises as fs } from 'fs'
import readline from 'readline'
import { chunk } from 'lodash-es'

/**
 * usage:
 *    tsx  <path>/.sources.mts  <target dir>
 */

let cwd: string = process.argv[2] ?? process.cwd()
if (!path.isAbsolute(cwd)) {
  cwd = path.join(process.cwd(), cwd)
}

const dirname = path.basename(cwd)


const prompt = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})


function ask({ index }: { index: number }): Promise<'yes' | 'no'> {
  return new Promise(resolve => {
    prompt.question(
      `[${index}] continue? ('no' to re-copy) [yes]/no `,
      input => resolve((input as 'yes' | 'no') || ''),
    )
  })
}

const pbcopy = async (data: string) => {
  var proc = spawn('pbcopy')
  await proc.stdin.write(data)
  await proc.stdin.end()
}


const walk = async ({
  dir,
  prefix = '',
  files = [],
}:{
  dir: string;
  prefix?: string;
  files?: string[];
}): Promise<string[]> => {
  for await (const entry of await fs.opendir(dir)) {
    if (entry.isDirectory()) {
      await walk({
        dir: path.join(dir, entry.name),
        prefix: path.join(prefix, entry.name),
        files,
      })
    }
    else if (entry.isFile() || entry.isSymbolicLink()) {
      files.push(path.join(prefix, entry.name))
    }
  }
  return files
}



const files = (await walk({ dir: cwd }))
  .filter(name => /(?<!test)\.ts$/.test(name))

const pathOfFile = (name: string) => path.join('.', dirname, name)


const codes = await Promise.all(
  files
  .map(async file => ({
    file,
    code: await fs.readFile(path.join(cwd, file), { encoding: 'utf-8' }),
  }))
)

type Item = {
  file: string;
  code: string;
}

const chunkSize = 10
const chunks: Item[][] = chunk(codes, chunkSize)

console.log(`
  total files: ${files.length}
  total chunks: ${chunks.length} (chunk size ${chunkSize})
`)

for (const [index, chunk] of chunks.entries()) {
  const paste = chunk
    .map(({ file, code }) => [
      `// ${pathOfFile(file)}`,
      code,
    ].join('\n'))
    .join('\n-----\n')
  await pbcopy(paste)
  while (await ask({ index }) === 'no') {
    await pbcopy(paste)
  }
}