import { ensureDir, readFileSync, writeFileSync } from 'fs-extra';
import { task, types } from 'hardhat/config';
import { initEnv, waitForTx } from '../helpers/utils';
import { join } from 'path';

import config from '../hardhat.config';
import { dump,load } from 'js-yaml';



interface ICONTRACT_DEPLOY {
  artifactsPath: string;
  name: string;
  ctor?: any;
  jsonName: string;
}

const processDir = process.cwd();
const subgraphPath = join(processDir, '../add-ons/subgraph/');
const abiPath = join(subgraphPath, 'abis');
ensureDir(abiPath);
const srcPath = join(subgraphPath, 'src');
const contract_path_relative = '../<%= sourceRoot %>/assets/contracts/';
const contract_path = join(processDir, contract_path_relative);
ensureDir(contract_path);

task('publish', 'publish subgraph')
.addOptionalParam("reset","reset yaml file", false, types.boolean)
.setAction(async (taskArgs, hre) => {
 let reset = taskArgs.reset;
 {


  

  let network = hre.network;
  if (network == undefined) {
    network = config.defaultNetwork;
  }

  const contract_config = JSON.parse(
    readFileSync(join(processDir, 'contract.config.json'), 'utf-8')
  ) as { [key: string]: ICONTRACT_DEPLOY };

  const deployContracts=["<%= contractCode %>"]

  // Hardhat always runs the compile task when running scripts with its command
  // line interface.
  //
  // If this script is run directly using `node` you may want to call compile
  // manually to make sure everything is compiled
  // await hre.run('compile');

  for (const toDeployName of deployContracts) {
    const toDeployContract = contract_config[toDeployName];
    if (toDeployContract == undefined) {
      console.error('Your contract is not yet configured');
      console.error(
        'Please add the configuration to /hardhat/contract.config.json'
      );
      return;
    }

    const metadata = JSON.parse(
      readFileSync(
        `${contract_path}/${toDeployContract.jsonName}_metadata.json`,
        'utf-8'
      )
    );

    const doc = load(
      readFileSync(join(subgraphPath, 'subgraph.yaml'), 'utf8')
    ) as any;
    const dataSources = doc['dataSources'];

    dataSources.name = toDeployContract.name;

    const contract_key = dataSources.filter(
      (fil: any) => fil.kind == 'ethereum/contract'
    )[0];

    contract_key.name = toDeployContract.name;

    const contractSource = contract_key.source;
    contractSource.address = metadata.address;
    contractSource.abi = toDeployContract.name;

    const contractMapping = contract_key.mapping;

    if (contractMapping.kind == 'ethereum/events') {
      /////// prepare events
      const events = metadata.abi.filter((fil: any) => fil.type == 'event');

 
      if (reset == true){
        contractMapping.eventHandlers = [];
      }
      let yamlEvents = contractMapping.eventHandlers

      console.log(yamlEvents);

      for (const contractEvent of events) {
        const inputsStringRaw = contractEvent.inputs
          .map((input: any) => input.type)
          .reduce(
            (prev: any, current: any) => (current = prev + current + ','),
            ''
          ) as string;

        yamlEvents.push({
          event: `${contractEvent.name}(${inputsStringRaw.substring(0, inputsStringRaw.length - 1)})`,
          handler: `handle${contractEvent.name}`,
        });
      }
      console.log(yamlEvents);
      contractMapping.eventHandlers = yamlEvents;


 
      if (reset == true) {
        contractMapping.abis = [];
      }
      let abis = contractMapping.abis
      
     
      const newAbiEntry = {
        name: toDeployContract.name,
        path: `./abis/${toDeployContract.jsonName}.json`,
      };
      if(abis.filter((fil:any)=> fil.path == newAbiEntry.path).length == 0){
        abis.push(newAbiEntry);
      }
      
      writeFileSync(join(abiPath,`${toDeployContract.jsonName}.json`),JSON.stringify(metadata.abi));
    }

    writeFileSync(join(subgraphPath,'subgraph.yaml'), dump(doc))
  }
}

});
