const glob = require( 'glob' );
const path = require( 'path' );
const fs = require( 'fs-extra' );
const config = require( '../tribes/townconf.js' );

const Referentials = {};
/*
Manage Referential object data

each object is compose of a list of fields
each fields have it owns structur and check
those common rules allow to be used to manage:
- forms (creation to collect data)
- data check
- data access rights
common referential data stored in /data/shared/referential/

*/
Referentials.clientconf = ( xworkOn, listkey ) => {
	/*
	Retourne les info d'un clientconf.json sur une liste de [cle]
	*/
	let conf = {};
	let dataconf = {};
	//logger.info( `${config.tribes}/${xworkOn}/clientconf.json` )
	try {
		conf = fs.readJsonSync( `${config.tribes}/${xworkOn}/clientconf.json` );
		// remove information notrelevant for
    [ 'emailFrom', 'emailClient', 'emailCc', 'commentkey', 'clezoomprivate', 'stripekeyprivate', 'genericpsw' ].forEach( c => {
			delete conf[ c ];
		} );
		listkey.forEach( k => dataconf[ k ] = conf[ k ] )
		//logger.info( 'dataconf', dataconf )
	} catch ( err ) {
		logger.info( 'Attention demande sur clienId inconnu ' + xworkOn );
	}
	return {
		status: 200,
		payload: {
			data: dataconf
		}
	};
};
Referentials.clientconfglob = () => ( {
	status: 200,
	payload: {
		data: fs.readJsonSync( `${config.tmp}/clientconfglob.json` )
	}
} );
Referentials.getref = ( origin, source, ref, xworkOn, xlang ) => {
	// If request origin then send back referential with all language in it
	// if not origin or json source return by language
	let referent = {};
	let src;
	if( origin && [ 'object', 'data' ].includes( source ) ) {
		src = `${config.tribes}/${xworkOn}/referentials/${source}/${ref}.json`
	} else {
		src = `${config.tribes}/${xworkOn}/referentials/${source}/${ref}_${xlang}.json`;
	}
	//logger.info( src )
	try {
		referent = fs.readJsonSync( src );
	} catch ( err ) {
		logger.info( `Request  ${src} does not exist  ` );
	}
	return {
		status: 200,
		payload: {
			data: referent
		}
	};
};
Referentials.putref = ( source, name, xworkOn, data ) => {
	/*
	We get a referential, we have 3 kinds of sources:
	 * data = [{uuid,DESC:{fr:,en,},DESCLONG:{fr:,en:}, other field}]
	        only DESC and DESCLONG have a translation
	 * json = are full complex object in language name_lg.json
	 * object = [{uuid,DESC:{fr,en},DESCLONG:{fr,en}},tpl,}]
	Difference between data and object is that object defines rule to manage an object, and how to create a forms to get data each data is saved in one folder object/uuid.json and have to respect the corresponding object referentials definition.

	For data and object it is possible only to put a file with all language available.
	When store this script erase with the new file per _lg

  name for source=json must end by _lg
	*/
	//logger.info( data )
	const pat = /.*_..\.json$/;
	const file = `${config.tribes}/${xworkOn}/referentials/${source}/${name}.json`
	if( [ 'object', 'data' ].includes( source ) ) {
		if( pat.test( name ) ) {
			return { status: 404, payload: { model: 'Referentials', info: [ 'nameunconsistent' ], moreinfo: "can not be update with one lang need a full file with language for object or data" } }
		} else {
			fs.outputJsonSync( file, data );
			return Refernetials.update( xworkOn, source, name )
		}
	} else {
		if( !pat.test( name ) ) {
			return { status: 404, payload: { model: 'Referentials', info: [ 'nameunconsistent' ], moreinfo: "can not be update without a lang _lg.json a referential json" } }
		} else {
			fs.outputJsonSync( file, data );
			return { status: 200, payload: { model: 'Referentials', info: [ 'successfull' ], moreinfo: "ref json updated " } }
		}
	};
};
Referentials.updatefull = ( tribeid ) => {
	let err = "";
	let nbrefupdate = 0;
	const pat = /.*_..\.json$/;
	 [ 'object', 'data' ].forEach( o => {
		glob.sync( `${config.tribes}/${tribeid}/referentials/${o}/*.json` )
			.forEach( f => {
				if( !pat.test( f ) ) {
					const res = Referentials.update( tribeid, o, path.basename( f, '.json' ) );
					if( res.status != 200 ) {
						err += `Error on ${o}/${path.basename(f)}`
					} else {
						nbrefupdate += 1;
					}
				}
			} )
	} );
	if( err != "" ) {
		return { status: 500, payload: { info: [ 'Errupdateref' ], model: "Referentials", moreinfo: err } }
	}
	return { status: 200, payload: { info: [ 'Success' ], model: "Referentials", moreinfo: `Number of object and data ref updated: ${nbrefupdate}` } }
};

Referentials.inittribeid = () => {
	logger.info( "Clientconf list for this server", `${config.tribes}/**/clientconf.json` );
	const TribesGlobalConfig = glob.sync( `${config.tribes}/**/clientconf.json` )
		.map( f => fs.readJsonSync( f ) );
	// store global conf for sharing to other api
	fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, TribesGlobalConfig, {
		spaces: 2
	} );
	return { status: 200, payload: { moreinfo: TribesGlobalConfig } }
}
Referentials.generetribeids = () => {
	const tribeids = [];
	fs.readJsonSync( `${config.tmp}/clientconfglob.json` )
		.forEach( c => {
			if( !tribeids.includes( c.tribeid ) ) tribeids.push( c.tribeid );
		} );
	fs.outputJsonSync( `${config.tmp}/tribeids.json`, tribeids );
	logger.info( `update ${config.tribes}/tribeids` );
	return tribeids;
}
Referentials.genereallowedDOM = () => {
	const confglob = fs.readJsonSync( `${config.tmp}/clientconfglob.json` );
	let allDom = [];
	confglob.forEach( c => {
		c.allowedDOMs.forEach( d => {
			if( !allDom.includes( d ) ) allDom = allDom.concat( d );
		} )
	} );
	return allDom;
};
/* A voir si encore necessaire pour générer un environnement identique
  sur un autre server

  // Génére les domaines s'ils n'existe pas dans le repertoire
  function genereEnvClient() {
    const confglob = fs.readJsonSync(
      `${config.sharedData}/clientconfglob.json`
    );
    confglob.forEach(function(c) {
      config.tribeidsConf[c.tribeid] = c;
      if (c.allowedURLs) {
        c.allowedURLs.forEach(u => {
          if (!config.allowedURLs.includes(u)) {
            config.allowedURLs.push(u);
          }
        });
      } else {
        logger.info('erreur de fichier config d\'un site pour ', c);
      }
      // GLOBAL Tribes IDS INDEX
      maketribeidsIndex();
      if (!fs.existsSync(`${config.tribes}/${c.tribeid}`)) {
        const execSync = require('child_process').execSync;
        execSync(`cp -r ${config.tribes}/modele ${config.tribes}/${c.tribeid}`);
      }
    });
  }



  */
Referentials.update = ( tribeid, source, name ) => {
	/*
	Replace for each language the referential name for a tribeid
	After each update the version number is incremented by 1 in clientconf.json
	*/
	if( !fs.existsSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` ) ) {
		return { status: 500, payload: { info: [ "unknownRef" ], model: "Referentials", moreinfo: `file does not exist ${config.tribes}/${tribeid}/referentials/${source}/${name}.json` } }
	};

	const clientconf = fs.readJsonSync( `${config.tribes}/${tribeid}/clientconf.json` );
	if( !clientconf.langueReferential ) {
		return { status: 500, payload: { info: [ "missingConf" ], model: "Referentials", moreinfo: ` ${config.tribes}/${tribeid}/clientconf.json does not contain langueReferential array` } }
	}
	const ref = fs.readJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` );

	clientconf.langueReferential.forEach( lg => {
		//manage translation
		let refnew = [];

		refnew = [];
		ref.forEach( d => {
			if( d.DESC ) d.DESC = d.DESC[ lg ];
			if( d.DESCLONG ) d.DESCLONG = d.DESCLONG[ lg ];
			if( d.INFO ) d.INFO = d.INFO[ lg ];
			if( d.desc ) d.desc = d.desc[ lg ];
			if( d.desclong ) d.desclong = d.desclong[ lg ];
			if( d.info ) d.info = d.info[ lg ];
			if( d.placeholder ) d.placeholder = d.placeholder[ lg ];
			refnew.push( d )
		} )
		//save new ref in language
		//logger.info( "New ref", refnew )
		logger.info( `Update referentials per lg ${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json` )
		fs.outputJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json`, refnew, {
			spaces: 2
		} );
	} );
	//upgrade version number
	if( !clientconf.referentials ) clientconf.referentials = {};
	if( !clientconf.referentials[ source ] ) clientconf.referentials[ source ] = {};
	if( !clientconf.referentials[ source ][ name ] ) clientconf.referentials[ source ][ name ] = { version: 0 };
	clientconf.referentials[ source ][ name ].version += 1;
	fs.outputJsonSync( `${config.tribes}/${tribeid}/clientconf.json`, clientconf, 'utf8' );
	return {
		status: 200,
		payload: {
			info: [ 'successUpdate' ],
			model: "Referentials",
			moreinfo: `${name} updated`
		}
	}
};
//logger.info( Referentials.update( 'apixtribe', "object", "user" ) )

Referentials.genereobjet = ( tribeid, destination, tplmustache, objet, filtre ) => {
	/* @TODO
	 Genere des objets d'agregat
	 @tribeid = data/tribee/ identifiant client
	 @destinations = [] of destination
	 @tplmustache = fichier mustache de mise en page
	 @objet =   nom d'objet contact, companies, items, users
	 @filtre = fonction a executer
	*/
}

//////// EN DESSOUS DE CETTE LIGNE A SUPPRIMER

/*
Le principe consistait à partager des referentiels dans shareddataLa gestion est trop compliqué => le principe chaque client duplique un referentiel pour que les app qui s'appuie sur des composants communs puissent fonctionner

*/

/*Referentials.genereClientObjectASUPP = () => {
	const confglob = fs.readJsonSync( `${config.tmp}/clientconfglob.json` );
	// Check and update folder and data per lang
	// c as tribeid
	confglob.forEach( ( c, postribeid ) => {
		//check folder are well create
		const lstfolder = [ 'actions', 'actions/done', 'actions/todo', 'cards', 'logs', 'orders', 'orders/reservation', 'orders/purchase', 'orders/contact', 'public', 'public/reservation', 'tags', 'tags/stats', 'tags/archives', 'tags/hits', 'tags/imgtg', 'users' ];
		lstfolder.forEach( fol => {
			if( !fs.existsSync( `${config.tribes}/${c.tribeid}/${fol}` ) ) {
				fs.mkdirSync( `${config.tribes}/${c.tribeid}/${fol}` );
			}
		} )
		if( c.referentials && !c.langue ) { logger.info( `ERREUR referentials mais pas de langue:[] pour ${c.tribeid}/clientconf.json` ) }
		if( c.referentials && c.langue ) {
			let majclientconf = false;
			// Create and check Object structure
			Object.keys( c.referentials.object )
				.forEach( o => {
					// if object exist in shared then it merge sharedObject and domain referential object
					let objfull = [];
					const objshared = `${config.sharedData}/referentials/dataManagement/object/${o}.json`;
					if( fs.existsSync( objshared ) ) {
						objfull = objfull.concat( fs.readJsonSync( objshared ) );
					}
					const objdomain = `${config.tribes}/${c.tribeid}/referentials/dataManagement/object/${o}.json`;
					if( fs.existsSync( objdomain ) ) {
						objfull = objfull.concat( fs.readJsonSync( objdomain ) );
					}
					c.langue.forEach( lg => {
						const objfulllg = objfull.map( field => {
							if( field.DESC ) field.DESC = field.DESC[ lg ];
							if( field.DESCLONG ) field.DESCLONG = field.DESCLONG[ lg ];
							return field;
						} );
						const objectdomlg = `${config.tribes}/${c.tribeid}/referentials/${lg}/object/${o}.json`;
						let savedObject = {};
						if( fs.existsSync( objectdomlg ) ) {
							savedObject = fs.readJsonSync( objectdomlg );
						}
						// TODO Always true change later to update only if needded
						if( !fs.existsSync( objectdomlg ) || objfulllg.length !== savedObject.length || 1 == 1 ) {
							fs.outputJsonSync( objectdomlg, objfulllg, {
								spaces: 2
							} );
							confglob[ postribeid ].referentials.object[ o ].version += 1;
							majclientconf = true;
						}
					} );
				} );
			// datafile
			Object.keys( c.referentials.data )
				.forEach( d => {
					// if object exist in shared then it merge sharedObject and domain referential object
					// logger.info(c.tribeid + '--' + d);
					let datafull = [];
					const datashared = `${
          config.sharedData
        }/referentials/dataManagement/data/${d}.json`;
					if( fs.existsSync( datashared ) ) {
						datafull = datafull.concat( fs.readJsonSync( datashared ) );
					}
					const datadomain = `${config.tribes}/${
          c.tribeid
        }/referentials/dataManagement/data/${d}.json`;
					if( fs.existsSync( datadomain ) ) {
						datafull = datafull.concat( fs.readJsonSync( datadomain ) );
					}
					/* const defdata = `${config.tribes}/${
					  c.tribeid
					}/referentials/dataManagement/data/${d}.json`;
					*/
// for each Langues => generate fr.obj and compare it with existing file
// if diff then => upgrade version number in clientconf
// logger.info(datafull);
// this could be improved by usind d.meta wich is the object that DESCribe this data
/*				c.langue.forEach( lg => {
						let meta;
						if( c.referentials.data[ d ].meta ) {
							meta = fs.readJsonSync( `${config.tribes}/${c.tribeid}/referentials/${lg}/object/${
                c.referentials.data[d].meta
              }.json` );
						}
						let datalg;
						const datafulllg = datafull.map( tup => {
							datalg = {};
							meta.forEach( ch => {
								if( tup[ ch.idfield ] ) {
									if( ch.multilangue ) {
										datalg[ ch.idfield ] = tup[ ch.idfield ][ lg ];
									} else {
										datalg[ ch.idfield ] = tup[ ch.idfield ];
									}
								}
							} );
							return datalg;
						} );
						// lit le fichier correspondant et le compare si différent le sauvegarde
						// stocke l'information d'upgrade d ela version
						const datadomlg = `${config.tribes}/${
            c.tribeid
          }/referentials/${lg}/data/${d}.json`;
						let saveddata = {};
						if( fs.existsSync( datadomlg ) ) {
							saveddata = fs.readJsonSync( datadomlg );
						}
						// Condition to improve
						// TODO always change file to improvelater by detecting real change.
						if( !fs.existsSync( datadomlg ) || datafulllg.length != saveddata.length || 1 == 1 ) {
							fs.outputJsonSync( datadomlg, datafulllg, {
								spaces: 2
							} );
							confglob[ postribeid ].referentials.data[ d ].version += 1;
							majclientconf = true;
						}
					} );
				} );
			// json file that have to start with lg {lg:'':{json }}
			Object.keys( c.referentials.json )
				.forEach( j => {
					// if object exist in shared then it merge sharedObject and domain referential object
					// logger.info(c.tribeid + '--' + d);
					let jsonfull = [];
					const jsondomain = `${config.tribes}/${c.tribeid}/referentials/dataManagement/json/${j}.json`;
					if( fs.existsSync( jsondomain ) ) {
						jsonfull = fs.readJsonSync( jsondomain );
					}
					c.langue.forEach( lg => {
						const jsondomlg = `${config.tribes}/${
            c.tribeid
          }/referentials/${lg}/json/${j}.json`;
						// logger.info('jsondomlg', jsondomlg);
						let datalg = jsonfull;
						if( jsonfull[ lg ] ) {
							datalg = jsonfull[ lg ];
						}
						fs.outputJsonSync( jsondomlg, datalg, {
							spaces: 2
						} );
					} );
				} );
			// update clientconf domain with updated version
			if( majclientconf ) {
				fs.outputJsonSync( `${config.tribes}/${c.tribeid}/clientconf.json`, c, {
					spaces: 2
				} );
			}
		}
	} );
	// update global conf
	fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, confglob, {
		spaces: 2
	} );
};*/

module.exports = Referentials;
