// @flow
import * as React from 'react';
import {
	Row,
	Col,
	Button,
	Form, FormGroup,
	Label, Input,
	Card, CardHeader, CardBody,
	TabContent, TabPane, Nav, NavItem, NavLink,
	Alert,
	UncontrolledDropdown, DropdownToggle, DropdownMenu,
	InputGroup, InputGroupAddon,
} from 'reactstrap';

import { connect } from 'react-redux';

import cn from 'classnames';

import { changeObjFieldName, generateNewKey, copyObj } from '@helpers';
import { BUILTIN_TYPES, ANALYZER_RESULT_TYPES, getValidPlotterObj as getValidObj } from '@helpers/beat';
import type { BeatObject } from '@helpers/beat';

import * as Selectors from '@store/selectors.js';

import * as Actions from '@store/actions.js';
import CacheInput from '../CacheInput.jsx';
import ValidSchemaBadge from '../ValidSchemaBadge.jsx';
import DeleteInputBtn from '../DeleteInputBtn.jsx';
import TypedField from '../TypedField.jsx';
import TemplateButton from '../EntityTemplateGenerationButton.jsx';
import InfoTooltip from '../InfoTooltip.jsx';
import ParameterCreate from '../ParameterCreate.jsx';

type Props = {
	data: BeatObject,
	libraries: BeatObject[],
	plotDfNames: string[],
	saveFunc: (BeatObject) => any,
	updateFunc: (BeatObject) => any,
};

type State = {
	choiceCache: string,
};

export class PlotterEditor extends React.Component<Props, State> {
	constructor(props: Props) {
		//console.log(`Creating AlgDetail`);
		super(props);
	}

	state = {
		choiceCache: '',
	}

	setContents = (newContents: any) => {
		this.props.updateFunc({
			...this.props.data,
			contents: {
				...this.props.data.contents,
				...newContents,
			}
		});
	}

	updateDescription = (desc: string) => {
		this.setContents({ description: desc });
	}

	updateDataformat = (df: string) => {
		this.setContents({ dataformat: df });
	}

	// 4 different functions:
	// creates a parameter (provide name & value)
	// updates a parameter (provide name & value)
	// renames a parameter (provide name & value & the old name)
	// deletes a parameter (provide null as name, value is optional, the name)
	updateParameter = (name: null | string, value: any, oldName: ?string) => {
		const params = copyObj(this.props.data.contents.parameters);
		if(oldName)
			delete params[oldName];
		if(name !== null)
			params[name] = value;
		this.setContents({ parameters: params });
	}

	// helper to change a value in the "contents" subobject of a plotter
	// (this is where the vast majority of change happens)
	changeContentsVal = (field: string, val: any) => {
		const newCache = {
			...this.props.data,
			contents: {
				...this.props.data.contents,
				[field]: val
			}
		};

		this.props.updateFunc(newCache);
	}


	renderLibraries = () => (
		<TabPane tabId='2'>
			<Row>
				<Col sm='12'>
					{
						// loop through all the used libs
						(Object.entries(this.props.data.contents.uses): [string, any][])
						.map(([name, lib], i, lEntries) => (
							<TypedField
								key={i}
								name={name}
								type={lib}
								types={this.props.libraries.map(l => l.name)}
								existingFields={lEntries.map(([n, v]) => n)}
								nameUpdateFunc={str => {
									// update the alias
									this.changeContentsVal('uses',
										changeObjFieldName(
											this.props.data.contents.uses,
											name,
											str
										)
									);
								}}
								typeUpdateFunc={str => {
									// update the chosen library for the alias
									const libs = {
										...this.props.data.contents.uses,
										[name]: str
									};
									this.changeContentsVal('uses', libs);
								}}
								deleteFunc={() => {
									const libs = { ...this.props.data.contents.uses };
									delete libs[name];
									this.changeContentsVal('uses', libs);
								}}
							/>
						))
					}
				</Col>
			</Row>
			<Button outline block
				id='newLibraryBtn'
				onClick={() => {
					const newKey = generateNewKey('library', Object.keys(this.props.data.contents.uses));
					this.changeContentsVal('uses',
						{
							...this.props.data.contents.uses,
							[newKey]: ''
						}
					);
				}}
			>
				New Library
			</Button>
		</TabPane>
	);


	render = () => {
		return (
			<div>
				<div className='d-flex'>
					<Button
						className='mx-auto'
						outline
						color='secondary'
						onClick={() => this.props.saveFunc(this.props.data)}
					>
						Save Changes (Changes are <ValidSchemaBadge entity='plotter' obj={this.props.data} />)
					</Button>
					<TemplateButton
						data={this.props.data}
						entity={'plotter'}
					/>
				</div>
				<Form>
					<FormGroup tag='fieldset'>
						<FormGroup>
							<Label>Short Description</Label>
							<Input
								type='text'
								id='plDesc'
								placeholder='Plotter description...'
								value={this.props.data.contents.description}
								onChange={(e) => this.updateDescription(e.target.value)}
							/>
						</FormGroup>
						<FormGroup>
							<Label>Input Dataformat</Label>
							<Input
								id='plDf'
								type='select'
								className='custom-select'
								value={this.props.data.contents.dataformat}
								onChange={e => this.updateDataformat(e.target.value)}
							>
								{
									this.props.plotDfNames.map((df, i) =>
										<option key={i} value={df}>{ df }</option>
									)
								}
							</Input>
						</FormGroup>
						<FormGroup id='usedLibs'>
							<h5>Libraries</h5>
								{ this.renderLibraries() }
						</FormGroup>
						<FormGroup id='paramsForm'>
							<h5>Parameters</h5>
							{
								(Object.entries(this.props.data.contents.parameters): [string, any][]).map(([name, param], i, params) => (
									<Row key={i} className='mb-2'>
										<Col sm='12'>
											<ParameterCreate
												name={name}
												param={param}
												params={params}
												updateParameter={this.updateParameter}
											/>
										</Col>
									</Row>
								))
							}
							<Button outline block
								id='newParameterBtn'
								onClick={() => {
									const newKey = generateNewKey('parameter', Object.keys(this.props.data.contents.parameters || {}));
									this.updateParameter(
										newKey,
										{
											type: '',
											default: '',
											description: '',
										}
									);
								}}
							>
								New Parameter
							</Button>
						</FormGroup>
					</FormGroup>
				</Form>
			</div>
		);
	}
}

const mapStateToProps = (state, ownProps) => {
	const plotters = Selectors.plotterGet(state);
	const obj = {
		libraries: Selectors.libraryGet(state),
		plotDfNames: Selectors.dataformatGet(state).map(df => df.name).filter(df => df.startsWith('plot/')),
		data: plotters[ownProps.index] || getValidObj(),
	};

	if(obj.data.contents.dataformat === "")
	{
		obj.plotDfNames.unshift("-- select an option --")
	};

	return obj;
};

const mapDispatchToProps = (dispatch, ownProps) => ({
	// replace the obj in the Redux store with the new object
	updateFunc: (obj) => {
		console.log(`dispatching for ${ obj.name }`);
		dispatch(Actions[`plotterUpdate`](obj.name, obj));
	},
});

export default connect(mapStateToProps, mapDispatchToProps)(PlotterEditor);
