import * as CommonFunctions from '../common-functions/common-functions';
import * as Models from '../models/models';

export class CollectJsons {
  private userProperties: Models.UserProperties;

  public constructor ( userProperties: Models.UserProperties ) {
    this.userProperties = userProperties;
  }

  public async createJoinedJson(): Promise<Models.Feature[]> {
    const jsonOutput = Array<Models.Feature>();

    await CommonFunctions.fileSystemFunctions.checkFolder( this.userProperties.jsonDir );
    const fileList = await this.getJsonReportFiles();

    if ( fileList.length === 0 ) {
      throw new Error( `No JSON files found in '${this.userProperties.jsonDir}'. NO REPORT CAN BE CREATED!` );
    }

    fileList.forEach( json => {
      json.forEach( feature => {
        if( feature.metadata === null || typeof feature.metadata === 'undefined' ){
          feature.metadata = [];
        }

        if( !this.isMetadata( feature.metadata ) ){
          feature.metadata = [];
        }

        if ( this.isMetadata( this.userProperties.metadata ) ) {
          feature.metadata.concat( this.userProperties.metadata );
        }
        feature.id = feature.id.toString().replace( '/', '_' );
        jsonOutput.push( feature );
      } );
    } );

    if ( this.userProperties.saveCollectedJSON ) {
      await CommonFunctions.fileSystemFunctions.saveJsonFile( this.userProperties.reportPath, '/merged-output.json' , jsonOutput );
    }

    return jsonOutput;
  }

  private getJsonReportFiles = async (): Promise<( Models.Feature[] )[]> => {
    let files = await CommonFunctions.fileSystemFunctions.getFilesAsync( this.userProperties.jsonDir );
    files = files.sort();
    const validReportsList = files.filter( file => file.endsWith( '.json' ) );

    const validReports = await Promise.all(
      validReportsList.map( async element => {
        const result = await CommonFunctions.fileSystemFunctions.readJsonFeatureFile( element, 'utf8' );
        const resultFiltered = Array.isArray( result ) && result
          ? result.filter( x => typeof x.id !== 'undefined' && x.id !== null && typeof x.keyword !== 'undefined' && x.keyword !== null )
          : null;
        return Array.isArray( resultFiltered ) && resultFiltered.length > 0 ? resultFiltered : null;
      } )
    );
    const filteredReports: Models.Feature[][] = validReports.filter( ( x ): x is Models.Feature[] => x !== null );
    return filteredReports;
  };

  private isMetadata( metadata: Models.Metadata[] | undefined ): metadata is Models.Metadata[]{
    return !Array.isArray( metadata ) ? false : metadata.filter( metadataElement =>
      ( metadataElement ).name === undefined || ( metadataElement ).value === undefined ).length === 0;
  }
}
