// @flow
// API helpers not tied to any specific library
import { pluralize } from './beat.js';
import type { BeatEntity } from './beat.js';
import type { StringObject } from '.';

export type Fetchable = BeatEntity | 'settings' | 'environments';

const fetchConfig = {
	mode: 'cors'
};

let port = '5000';

export const toUrl = (str: string) => `http://127.0.0.1:${ port }/${ str }`;

// curried func for calling the REST API
// basically:
// <response> = genApiCall(<http rest verb>)(<endpoint>)(<payload if any>)
const genApiCall = (method) => (be: Fetchable) => async (obj: any) => {
	const validMethods = ['GET', 'POST', 'PUT', 'DELETE'];
	if(!validMethods.includes(method))
		throw new Error(`invalid method: ${ method }`);
	const headers = new Headers();
	if(method !== 'GET')
		headers.append('Content-Type', 'application/json');
	const config = {
		headers,
		...fetchConfig,
		...{
			method,
			body: obj ? JSON.stringify(obj) : obj
		}
	};

	const seg = be === 'settings' || be === 'environments' ? be : pluralize(be);
	let res = await fetch(toUrl(seg), config);
	let json = await res.json();
	console.log(json);
	return json;
};

// sets the port number for api calls
export const setPort = (newPort: number) => {
	port = newPort;
};

// gens all the default API funcs for an endpoint
export const genModuleApiFuncs = (be: Fetchable) => {
	return {
		get: genApiCall('GET')(be),
		post: genApiCall('POST')(be),
		put: genApiCall('PUT')(be),
		delete: genApiCall('DELETE')(be),
	};
};

// fetches layout info from graphviz for a toolchain
const layoutUrl = toUrl('layout');
export const fetchLayout = async (tcName: string) => {
	const layoutConfig = {
		headers: {
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		method: 'POST',
		body: JSON.stringify({ toolchain: tcName }),
	};
	const res = await fetch(layoutUrl, layoutConfig);
	const json = await res.json();
	return JSON.parse(json);
};

// generates a python file from a template given some args payload
const templatesUrl = toUrl('templates');
// given the BEAT entity and a dict of args, tries to generate a python file from a template
// returns either the response if successful or `false` if the python file already exists
const generateTemplate = async (be: string, args: {[string]: any}) => {
	const templatesConfig = {
		headers: {
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		method: 'POST',
		body: JSON.stringify({ entity: be, ...args}),
	};
	const res = await fetch(templatesUrl, templatesConfig);
	if(res.status === 200){
		// okay
		const json = await res.json();
		return JSON.parse(json);
	} else {
		if(res.status === 409){
			// python file already exists, return false to let callers know
			return false;
		}
	}
};

export const generateDatabaseTemplate = async (name: string, confirm: boolean, views: string[]) => {
	return generateTemplate('databases', {name, views, confirm});
};

export const generateAlgorithmTemplate = async (name: string, confirm: boolean, contents: any) => {
	return generateTemplate('algorithms', {name, contents, confirm});
};

export const generateLibraryTemplate = async (name: string, confirm: boolean, uses: StringObject) => {
	return generateTemplate('libraries', {name, uses, confirm});
};

export const generatePlotterTemplate = async (name: string, confirm: boolean, uses: StringObject) => {
	return generateTemplate('plotters', {name, uses, confirm});
};
