import * as fs from 'fs';
import * as path from 'path';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import dotenv from 'dotenv';

import { Registry } from '@cerc-io/registry-sdk';

dotenv.config();

const LACONICD_GQL_ENDPOINT = process.env.LACONICD_GQL_ENDPOINT || 'https://laconicd.laconic.com/api';
const LACONICD_RPC_ENDPOINT = process.env.LACONICD_RPC_ENDPOINT || 'https://laconicd.laconic.com';
const LACONICD_CHAIN_ID = process.env.LACONICD_CHAIN_ID || 'laconic_9000-1';

async function main(): Promise<void> {
  const argv = _getArgv();

  const registry = new Registry(LACONICD_GQL_ENDPOINT, LACONICD_RPC_ENDPOINT, LACONICD_CHAIN_ID);

  console.time('time_taken_getParticipants');
  const participants = await registry.getParticipants();
  console.log('Fetched participants, count:', participants.length);
  console.timeEnd('time_taken_getParticipants');

  let validators: Array<string> = await readValidators(argv.validatorsCsv);
  console.log('Read validators, count:', validators.length);

  let stage1Allocations: Array<{ 'cosmos_address': string, balance: string }> = [];

  const stage1Participants = participants.map((participant: any) => {
    const outputParticipant: any = {
      'cosmos_address': participant.cosmosAddress,
      'nitro_address': participant.nitroAddress,
      'kyc_id': participant.kycId
    };

    if (validators.includes(participant.cosmosAddress)) {
      outputParticipant.role = 'validator';

      stage1Allocations.push({
        cosmos_address: participant.cosmosAddress,
        balance: argv.validatorAlloc
      });

      // Remove processed participant from validators list
      validators = validators.filter(val => val !== participant.cosmosAddress);
    } else {
      outputParticipant.role = 'participant';

      stage1Allocations.push({
        cosmos_address: participant.cosmosAddress,
        balance: argv.participantAlloc
      });
    }

    return outputParticipant;
  });

  // Provide allocs for remaining validators
  validators.forEach(val => {
    stage1Allocations.push({
      cosmos_address: val,
      balance: argv.validatorAlloc
    });
  });

  const participantsOutputFilePath = path.resolve(argv.output);
  fs.writeFileSync(participantsOutputFilePath, JSON.stringify(stage1Participants, null, 2));
  console.log(`Onboarded participants with filtered validators written to ${participantsOutputFilePath}`);

  const allocsOutputFilePath = path.resolve(argv.outputAllocs);
  fs.writeFileSync(allocsOutputFilePath, JSON.stringify(stage1Allocations, null, 2));
  console.log(`Stage1 allocations written to ${allocsOutputFilePath}`);
}

async function readValidators(subscribersCsvPath: string): Promise<any> {
  const fileContent = fs.readFileSync(path.resolve(subscribersCsvPath), { encoding: 'utf-8' });
  return fileContent.split('\r\n').map(address => address.trim());
}

function _getArgv (): any {
  return yargs(hideBin(process.argv))
  .option('validatorsCsv', {
    type: 'string',
    demandOption: true,
    describe: 'Path to a CSV file with validators list',
  })
  .option('participantAlloc', {
    type: 'string',
    demandOption: true,
    describe: 'Participant stage1 balance allocation',
  })
  .option('validatorAlloc', {
    type: 'string',
    demandOption: true,
    describe: 'Validator stage1 balance allocation',
  })
  .option('output', {
    type: 'string',
    demandOption: true,
    describe: 'Path to the output JSON file',
  })
  .option('outputAllocs', {
    type: 'string',
    demandOption: true,
    describe: 'Path to the output JSON file with allocs',
  })
  .help()
  .argv;
}

main().catch(err => {
  console.log(err);
});
