import fs from "fs/promises";
import { DownloaderHelper } from "node-downloader-helper";
import path from "path";
import yargs from "yargs";

const binariesBaseDir
  = "https://github.com/inaturalist/model-files/releases/download/v25.01.15";

const androidExt = "tflite";
const iosExt = "mlmodel";
const cvModelFilename = "INatVision_Small_2_fact256_8bit";
const geomodelFilename = "INatGeomodel_Small_2_8bit";

const androidCV = `${binariesBaseDir}/${cvModelFilename}.${androidExt}`;
const iosCV = `${binariesBaseDir}/${cvModelFilename}.${iosExt}`;
const androidGeo = `${binariesBaseDir}/${geomodelFilename}.${androidExt}`;
const iosGeo = `${binariesBaseDir}/${geomodelFilename}.${iosExt}`;
const taxonomyCSV = `${binariesBaseDir}/taxonomy.csv`;
const taxonomyJSON = `${binariesBaseDir}/taxonomy.json`;

const downloadAndroid = async argv => {
  const androidFlavor = argv.androidFlavor || "debug";
  const androidDestination = path.join(
    __dirname,
    "..",
    "android",
    "app",
    "src",
    androidFlavor,
    "assets",
    "camera",
  );

  const androidModel = path.join(
    androidDestination,
    `${cvModelFilename}.${androidExt}`,
  );

  console.log( "Checking android model files..." );
  let exist = true;
  try {
    await fs.access( androidModel );
  } catch ( _ ) {
    exist = false;
  }

  if ( exist ) {
    console.log( "Android model exist!" );
    return;
  }

  console.log(
    `Android model files missing, downloading from '${binariesBaseDir}'...`,
  );

  await fs.mkdir( androidDestination, { recursive: true } );

  const dl = new DownloaderHelper( androidCV, androidDestination );
  dl.on( "end", () => console.log( "Download Completed" ) );
  dl.on( "error", err => console.log( "Download Failed", err ) );
  await dl.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );
  const dl2 = new DownloaderHelper( androidGeo, androidDestination );
  dl2.on( "end", () => console.log( "Download Completed" ) );
  dl2.on( "error", err => console.log( "Download Failed", err ) );
  await dl2.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );
  const dl3 = new DownloaderHelper( taxonomyCSV, androidDestination );
  dl3.on( "end", () => console.log( "Download Completed" ) );
  dl3.on( "error", err => console.log( "Download Failed", err ) );
  await dl3.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );

  console.log( "Android done!" );
};

const downloadIOS = async () => {
  const iosDestination = path.join( __dirname, "..", "ios" );

  const iosModel = path.join( iosDestination, `${cvModelFilename}.${iosExt}` );

  console.log( "Checking ios model files..." );
  let exist = true;
  try {
    await fs.access( iosModel );
  } catch ( _ ) {
    exist = false;
  }

  if ( exist ) {
    console.log( "ios model exist!" );
    return;
  }

  console.log(
    `iOS Model files missing, downloading from '${binariesBaseDir}'...`,
  );

  await fs.mkdir( iosDestination, { recursive: true } );

  const dl = new DownloaderHelper( iosCV, iosDestination );
  dl.on( "end", () => console.log( "Download Completed" ) );
  dl.on( "error", err => console.log( "Download Failed", err ) );
  await dl.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );
  const dl2 = new DownloaderHelper( iosGeo, iosDestination );
  dl2.on( "end", () => console.log( "Download Completed" ) );
  dl2.on( "error", err => console.log( "Download Failed", err ) );
  await dl2.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );
  const dl3 = new DownloaderHelper( taxonomyJSON, iosDestination );
  dl3.on( "end", () => console.log( "Download Completed" ) );
  dl3.on( "error", err => console.log( "Download Failed", err ) );
  await dl3.start().catch( err => console.error( err ) );
  console.log( "Downloaded!" );

  console.log( "iOS done!" );
};

// eslint-disable-next-line no-unused-expressions, @typescript-eslint/no-unused-expressions
yargs
  .usage( "Usage: $0 [args]" )
  .option( "androidFlavor", {
    alias: "f",
    type: "string",
    description: "Android flavor to download model files into",
  } )
  .command(
    "$0",
    "Download example model files if not present",
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    () => {},
    async argv => {
      await downloadAndroid( argv );
      await downloadIOS();
    },
  )
  .help().argv;
