import * as Models from '../models/models';
import * as fs from 'fs';
import * as fse from 'fs-extra';
import * as jsonFuture from 'json-future';
import * as path from 'path';
const fsp = fs.promises;

export class FileSystemFunctions {
  public getFilesAsync = async ( dir: string ): Promise<string[]> => {
    let files: string[] = [];
    const getFiles = async ( folder: string ): Promise<string[]> => {
      files = await fsp.readdir( folder );
      const result: Promise<string[]>[] = files.map( ( file ) => {
        const p = path.join( folder, file );
        return fsp.stat( p ).then( ( stat ) => ( stat.isDirectory() ? getFiles( p ) : [p] ) );
      } );
      return Array.prototype.concat( ...( await Promise.all( result ) ) ) as string[]; // Flatten
    };

    return getFiles( dir );
  };

  public checkFolder = async ( file: string| undefined ): Promise<boolean> =>{
    if( typeof file === 'undefined' ){
      return false;
    }

    await fsp.stat( file ).catch( ( ) =>{
      throw new Error( `The path provided: ${file} is invalid` );
    } );

    return true;
  };

  public readJsonFeatureFile = async ( file: string, encoding: string ): Promise<Models.Feature[]> =>
    fse.readJson( file, <fse.ReadOptions>{ encoding } ).catch( ( error: Error ) => {
      console.log( `The file ${file} is not a valid json, it has the error message ${error.message}` );
      return null;
    } ) as Promise<Models.Feature[]>;

  public readJsonExtendedReportFile = async ( file: string, encoding = 'utf8' ): Promise<Models.ExtendedReport> =>{
    const report = await fse.readJson( file, <fse.ReadOptions>{ encoding } ).catch( ( error: Error ) => {
      console.log( `The file ${file} is not a valid json, it has the error message ${error.message}` );
      throw new Error( `The file ${file} is not a valid json, it has the error message ${error.message}` );
    } ) as Models.ExtendedReport;
    report.results.overview.date = new Date( report.results.overview.date );

    return report;
  };

  public writeJson = async ( destinationFile: string, jsonObject: Models.ExtendedReport| string ): Promise<void> =>
    fse.writeFile( destinationFile, jsonObject );

  public saveJsonFile = async ( filePath: string | undefined, fileName: string, json: Models.Feature[] | Models.ExtendedReport ): Promise<boolean> => {
    const fileNameAndPath = path.join( filePath as string, fileName );
    const jsonString = jsonFuture.stringify( json );
    await this.writeJson( fileNameAndPath, jsonString );
    return true;
  };
}
