import { Octokit } from '@octokit/rest';

import * as fs from 'node:fs';

import { createGitHubTokenStrategy } from '../github-token';
import { ELECTRON_ORG, ELECTRON_REPO, ElectronReleaseRepo, NIGHTLY_REPO } from '../types';

if (process.argv.length < 6) {
  console.log('Usage: upload-to-github filePath fileName releaseId');
  process.exit(1);
}

const filePath = process.argv[2];
const fileName = process.argv[3];
const releaseId = parseInt(process.argv[4], 10);
const releaseVersion = process.argv[5];

if (isNaN(releaseId)) {
  throw new TypeError('Provided release ID was not a valid integer');
}

const getHeaders = (filePath: string, fileName: string) => {
  const extension = fileName.split('.').pop();
  if (!extension) {
    throw new Error(`Failed to get headers for extensionless file: ${fileName}`);
  }
  console.log(`About to get size of ${filePath}`);
  const size = fs.statSync(filePath).size;
  console.log(`Got size of ${filePath}: ${size}`);
  const options: Record<string, string> = {
    json: 'text/json',
    zip: 'application/zip',
    txt: 'text/plain',
    ts: 'application/typescript'
  };

  return {
    'content-type': options[extension],
    'content-length': size
  };
};

function getRepo (): ElectronReleaseRepo {
  return releaseVersion.indexOf('nightly') > 0 ? NIGHTLY_REPO : ELECTRON_REPO;
}

const targetRepo = getRepo();
const uploadUrl = `https://uploads.github.com/repos/electron/${targetRepo}/releases/${releaseId}/assets{?name,label}`;
let retry = 0;

let octokit = new Octokit({
  authStrategy: createGitHubTokenStrategy(targetRepo),
  log: console
});

function uploadToGitHub () {
  console.log(`in uploadToGitHub for ${filePath}, ${fileName}`);
  const fileData = fs.createReadStream(filePath);
  console.log(`in uploadToGitHub, created readstream for ${filePath}`);
  octokit.repos.uploadReleaseAsset({
    url: uploadUrl,
    headers: getHeaders(filePath, fileName),
    data: fileData as any,
    name: fileName,
    owner: ELECTRON_ORG,
    repo: targetRepo,
    release_id: releaseId
  }).then(() => {
    console.log(`Successfully uploaded ${fileName} to GitHub.`);
    process.exit();
  }).catch((err) => {
    if (retry < 4) {
      console.log(`Error uploading ${fileName} to GitHub, will retry.  Error was:`, err);
      retry++;

      // Reset octokit in case it cached an auth error somehow
      octokit = new Octokit({
        authStrategy: createGitHubTokenStrategy(targetRepo),
        log: console
      });

      octokit.repos.listReleaseAssets({
        owner: ELECTRON_ORG,
        repo: targetRepo,
        release_id: releaseId,
        per_page: 100
      }).then(assets => {
        console.log('Got list of assets for existing release:');
        console.log(JSON.stringify(assets.data, null, '  '));
        const existingAssets = assets.data.filter(asset => asset.name === fileName);

        if (existingAssets.length > 0) {
          console.log(`${fileName} already exists; will delete before retrying upload.`);
          octokit.repos.deleteReleaseAsset({
            owner: ELECTRON_ORG,
            repo: targetRepo,
            asset_id: existingAssets[0].id
          }).catch((deleteErr) => {
            console.log(`Failed to delete existing asset ${fileName}.  Error was:`, deleteErr);
          }).then(uploadToGitHub);
        } else {
          console.log(`Current asset ${fileName} not found in existing assets; retrying upload.`);
          uploadToGitHub();
        }
      }).catch((getReleaseErr) => {
        console.log('Fatal: Unable to get current release assets via getRelease!  Error was:', getReleaseErr);
        process.exitCode = 1;
      });
    } else {
      console.log(`Error retrying uploading ${fileName} to GitHub:`, err);
      process.exitCode = 1;
    }
  });
}

uploadToGitHub();
