#!/usr/bin/env node
import { execSync } from 'node:child_process'
import { closeSync, mkdtempSync, openSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { program } from 'commander'
import * as core from '@actions/core'
import { getOctokit } from '@actions/github'

async function run(action, owner, repo, pull_number, options = {}) {
  const token = execSync('gh auth token', { encoding: 'utf-8' }).trim()

  const github = getOctokit(token)

  const payload = !pull_number ? {} : {
    pull_request: (await github.rest.pulls.get({
      owner,
      repo,
      pull_number,
    })).data
  }

  process.env['INPUT_GITHUB-TOKEN'] = token

  closeSync(openSync('step-summary.md', 'w'))
  process.env.GITHUB_STEP_SUMMARY = 'step-summary.md'

  await action({
    github,
    context: {
      payload,
      repo: {
        owner,
        repo,
      },
    },
    core,
    dry: true,
    ...options,
  })
}

program
  .command('prepare')
  .description('Prepare relevant information of a pull request.')
  .argument('<owner>', 'Owner of the GitHub repository to check (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to check (Example: nixpkgs)')
  .argument('<pr>', 'Number of the Pull Request to check')
  .option('--no-dry', 'Make actual modifications')
  .action(async (owner, repo, pr, options) => {
    const prepare = (await import('./prepare.js')).default
    await run(prepare, owner, repo, pr, options)
  })

program
  .command('commits')
  .description('Check commit structure of a pull request.')
  .argument('<owner>', 'Owner of the GitHub repository to check (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to check (Example: nixpkgs)')
  .argument('<pr>', 'Number of the Pull Request to check')
  .option('--no-cherry-picks', 'Do not expect cherry-picks.')
  .action(async (owner, repo, pr, options) => {
    const commits = (await import('./commits.js')).default
    await run(commits, owner, repo, pr, options)
  })

program
  .command('bot')
  .description('Run automation on pull requests and issues.')
  .argument('<owner>', 'Owner of the GitHub repository to label (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to label (Example: nixpkgs)')
  .argument('[pr]', 'Number of the Pull Request to label')
  .option('--no-dry', 'Make actual modifications')
  .action(async (owner, repo, pr, options) => {
    const bot = (await import('./bot.js')).default
    const tmp = mkdtempSync(join(tmpdir(), 'github-script-'))
    try {
      process.env.GITHUB_WORKSPACE = tmp
      process.chdir(tmp)
      await run(bot, owner, repo, pr, options)
    } finally {
      rmSync(tmp, { recursive: true })
    }
  })

program
  .command('get-teams')
  .description('Fetch the list of teams with GitHub and output it to a file')
  .argument('<owner>', 'Owner of the GitHub repository to label (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to label (Example: nixpkgs)')
  .argument('[outFile]', 'Path to the output file (Example: github-teams.json). If not set, prints to stdout')
  .action(async (owner, repo, outFile, options) => {
    const getTeams = (await import('./get-teams.js')).default
    await run(getTeams, owner, repo, undefined, { ...options, outFile })
  })

program
  .command('lint-commits')
  .description('Lint for common errors in commit messages')
  .argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
  .argument('<pr>', 'Number of the Pull Request to run on')
  .action(async (owner, repo, pr, options) => {
    const checkCommitMessages = (await import('./lint-commits.js')).default
    await run(checkCommitMessages, owner, repo, pr, options)
  })

program
  .command('check-target-branch')
  .description('Check that the PR is made against the correct branch')
  .argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
  .argument('<pr>', 'Number of the Pull Request to run on')
  .action(async (owner, repo, pr, options) => {
    const checkTargetBranch = (await import('./check-target-branch.ts')).checkTargetBranch
    await run(checkTargetBranch, owner, repo, pr, options)
  })

program
  .command('manual-file-edits')
  .description("Error when files that shouldn't be edited manually are")
  .argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
  .argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
  .argument('<pr>', 'Number of the Pull Request to run on')
  .action(async (owner, repo, pr, options) => {
    const checkManualFileEdits = (await import('./manual-file-edits.js')).default
    await run(checkManualFileEdits, owner, repo, pr, options)
  })

await program.parse()
