// handle fetching "initial data" for a given user ... the initial data is the data
// we assume the client will need immediately upon login or confirmation, saving them
// the trouble of fetching it immediately afterwards

'use strict';

const RepoIndexes = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/modules/repos/indexes');
const StreamIndexes = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/modules/streams/indexes');
const CodeErrorIndexes = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/modules/code_errors/indexes');
const ArrayUtilities = require(process.env.CSSVC_BACKEND_ROOT + '/shared/server_utils/array_utilities');
const { awaitParallel } = require(process.env.CSSVC_BACKEND_ROOT + '/shared/server_utils/await_utils');

class InitialDataFetcher  {

	constructor (options) {
		Object.assign(this, options);
	}

	// fetch the initial data needed
	async fetchInitialData () {
		this.initialData = {};
		await this.getTeams();			// get the teams they are a member of
		await this.getCompanies();		// get the companies associated with these teams
		this.updateTeamPlans();			// copy company plan info to their teams
		// await this.getRepos();			// get the repos owned by their teams
		await this.getStreams();		// get streams owned by the teams
		return this.initialData;
	}

	// get the teams the user is a member of
	async getTeams () {
		const teamIds = this.user.get('teamIds') || [];
		if (teamIds.length === 0) {
			this.initialData.teams = [];
			return;
		}
		this.teams = await this.request.data.teams.getByIds(teamIds);
		this.initialData.teams = await this.request.sanitizeModels(this.teams);
	}

	// get the companies that own the teams
	async getCompanies () {
		const userCompanyIds = this.user.get('companyIds') || [];
		const teamCompanyIds = this.initialData.teams.map(team => team.companyId);
		const companyIds = ArrayUtilities.union(userCompanyIds, teamCompanyIds);
		if (companyIds.length === 0) {
			this.initialData.companies = [];
			return;
		}
		this.companies = await this.request.data.companies.getByIds(companyIds);
		this.initialData.companies = await this.request.sanitizeModels(this.companies);

		// there should only really be one of these, per one-user-per-org
		await Promise.all(this.companies.map(async company => {
			const sanitizedCompany = this.initialData.companies.find(c => c.id === company.id);
			sanitizedCompany.memberCount = await company.getCompanyMemberCount(this.request.data);
		}));
	}
	
	// copy company plan info to their teams ... we've moved plan info from the team to
	// the company object, but since the client is looking for it in the team object,
	// we'll copy it here in the returned data ... at some point, we may modify the
	// client to actually look for it in the company object, but this is a cheat for now
	updateTeamPlans () {
		for (let team of this.initialData.teams) {
			const company = this.companies.find(company => company.id === team.companyId);
			if (company) {
				['plan', 'trialStartDate', 'trialEndDate', 'planStartDate'].forEach(attribute => {
					team[attribute] = company.get(attribute);
				});
			}
		}
	}

	// get the repos owned by the teams the user is a member of
	async getRepos () {
		const teamIds = this.user.get('teamIds') || [];
		if (teamIds.length === 0) {
			this.initialData.repos = [];
			return;
		}
		const query = {
			teamId: this.request.data.repos.inQuery(teamIds)
		};
		const repos = await this.request.data.repos.getByQuery(
			query,
			{ hint: RepoIndexes.byTeamId }
		);
		this.initialData.repos = await this.request.sanitizeModels(repos);
	}
	
	// get team streams and streams associated with followed objects
	async getStreams () {
		const teamIds = this.user.get('teamIds') || [];
		if (teamIds.length === 0) {
			return [];
		}
		const streams = await this.request.data.streams.getByQuery(
			{
				teamId: this.request.data.streams.inQuery(teamIds)
			},
			{
				hint: StreamIndexes.byTeamId
			}
		);
		this.initialData.streams = await this.request.sanitizeModels(streams);
	}
}

module.exports = InitialDataFetcher;
