// @flow
import * as React from 'react';
import {
	Row,
	Col,
	Button,
	FormGroup,
	Label, Input,
	UncontrolledDropdown, DropdownToggle, DropdownMenu,
	InputGroup, InputGroupAddon,
} from 'reactstrap';

import { BUILTIN_TYPES } from '@helpers/beat';

import TypedField from './TypedField.jsx';

type Props = {
	name: string,
	param: any,
	params: any[],
	updateParameter: (name: string | null, parameter: any | null, oldName: ?string) => any,
};

type State = {
	choiceCache: string
};

export default class ParameterCreate extends React.Component<Props, State> {
	constructor(props: Props){
		super(props);
	}

	state = {
		choiceCache: '',
	}

	shouldComponentUpdate = (nextProps: Props, nextState: State) => {
		// basically PureComponent but not checking updateParameter func which wont change by itself
		// props check
		if(nextProps.name !== this.props.name || nextProps.param !== this.props.param || nextProps.params !== this.props.params)
			return true;
		// state check
		if(nextState.choiceCache !== this.state.choiceCache)
			return true;
		return false;
	}

	render = () => {
		const name = this.props.name;
		const param = this.props.param;
		const params = this.props.params;
		const updateParameter = this.props.updateParameter;

		let new_param = false;
		if (param.type == 'bool')
		{
			if(typeof(param.default) == 'string')
			{
				new_param = true;
			}
			else
			{
				new_param = false;
			}
		}

		return (
			<React.Fragment>
				<TypedField
					placeholder='Parameter name...'
					name={name}
					type={param.type}
					types={BUILTIN_TYPES}
					existingFields={params.map(([n, v]) => n)}
					nameUpdateFunc={str => updateParameter(str, param, name)}
					typeUpdateFunc={(str) => {
						const newParam = {
							...param,
							type: str
						};

						switch(newParam.type){
							case 'string':
								delete newParam['range'];
								break;
							case 'bool':
								delete newParam['range'];
								delete newParam['choice'];
								break;
							default:
								break;
						}

						updateParameter(name, newParam);
					}}
					deleteFunc={() => {
						updateParameter(null, null, name);
					}}

				>
					<Col>
						<Input
							type='text'
							placeholder='Description'
							value={param[name] || param.description || ''}
							onChange={(e) => updateParameter(name, {
								...param,
								description: e.target.value
							})}
						/>
					</Col>
				</TypedField>
				<FormGroup row className='ml-3'>
					{
						param.type !== 'bool' &&
							<Col sm='4'>
								<Label>Restrict to...</Label>
								<FormGroup check>
									<Row>
										<Col>
											<Label check>
												<Input
													type='checkbox'
													checked={Array.isArray(param.choice)}
													onChange={e => {
														const b = e.target.checked;
														const newParam = {...param};
														if(b){
															delete newParam['range'];
															newParam['choice'] = [];
														} else {
															delete newParam['choice'];
														}

														updateParameter(name, newParam);
													}}
												/>{' '}
												Choices
											</Label>
										</Col>
										{
											param.type !== 'string' &&
												<Col>
													<Label check className='ml-3'>
														<Input
															type='checkbox'
															checked={Array.isArray(param.range)}
															onChange={e => {
																const b = e.target.checked;
																const newParam = {...param};
																if(b){
																	delete newParam['choice'];
																	newParam['range'] = [0, 1];
																} else {
																	delete newParam['range'];
																}

																updateParameter(name, newParam);
															}}
														/>{' '}
														Range
													</Label>
												</Col>
										}
									</Row>
								</FormGroup>
							</Col>
					}
					{
						Array.isArray(param.choice) &&
							<Col sm='auto'>
								<Label>
									Choices
								</Label>
								<UncontrolledDropdown>
									<DropdownToggle caret>
										Choices List
									</DropdownToggle>
									<DropdownMenu className='p-0'>
										{
											param.choice
											.map((c, j) =>
												<InputGroup key={j}>
													<Input
														defaultValue={c}
														className='border-top-0 border-left-0 border-right-0 rounded-0'
														onSubmit={e => {
															e.preventDefault();
														}}
														onChange={e => {
															updateParameter(
																name,
																{
																	...param,
																	choice: param.choice.map((c, k) => k === j ? e.target.value : c)
																});
														}}
													/>
													<InputGroupAddon addonType='append'>
														<Button
															className='border-top-0 border-left-0 border-right-0 rounded-0'
															color='danger'
															onClick={e => {
																updateParameter(name,
																	{
																		...param,
																		choice: param.choice.filter((c, k) => k !== j)
																	}
																);
															}}
														>
															x
														</Button>
													</InputGroupAddon>
												</InputGroup>
											)
										}
										<Input
											placeholder='New Choice...'
											className='border-top-0 border-left-0 border-right-0 rounded-0'
											value={this.state.choiceCache}
											onSubmit={e => {
												e.preventDefault();
											}}
											onBlur={e => {
												if(this.state.choiceCache.length > 0)
													updateParameter(name,
														{
															...param,
															choice: [
																...param.choice,
																this.state.choiceCache
															]
														});
												this.setState({ choiceCache: '' });
											}}
											onChange={e => {
												this.setState({ choiceCache: e.target.value });
											}}
											onKeyPress={e => {
												if(e.key === 'Enter'){
													if(this.state.choiceCache.length > 0)
														updateParameter(name,
															{
																...param,
																choice: [
																	...param.choice,
																	this.state.choiceCache
																]
															}
														);
													this.setState({ choiceCache: '' });
												}
											}}
										/>
									</DropdownMenu>
								</UncontrolledDropdown>
							</Col>
					}
					{
						Array.isArray(param.range) &&
							<Col sm='4'>
								<Label>
									Range
								</Label>
								<FormGroup row>
									<Col>
										<InputGroup>
											<InputGroupAddon addonType='prepend'>Min</InputGroupAddon>
											<Input
												type='number'
												step={param.type.startsWith('float') ? 'any' : '1'}
												value={param.range[0]}
												onChange={e => {
													const num = Number.parseFloat(e.target.value);
													if(Number.isNaN(num))
														return;
													const max = param.range[1];
													if(num > max){
														return;
													}
													const newParam = {
														...param,
														range: [
															num,
															max,
														]
													};
													updateParameter(
														name,
														newParam
													);
												}}
												required
											/>
										</InputGroup>
									</Col>
									<Col>
										<InputGroup>
											<InputGroupAddon addonType='prepend'>Max</InputGroupAddon>
											<Input
												type='number'
												step={param.type.startsWith('float') ? 'any' : '1'}
												value={param.range[1]}
												required
												onChange={e => {
													const num = Number.parseFloat(e.target.value);
													if(Number.isNaN(num))
														return;
													const min = param.range[0];
													if(num < min){
														return;
													}
													const newParam = {
														...param,
														range: [
															min,
															num,
														]
													};
													updateParameter(
														name,
														newParam
													);
												}}
											/>
										</InputGroup>
									</Col>
								</FormGroup>
							</Col>
					}
					{ param.type !== 'bool' &&
							<Col>
								<Label for={`default${ name }`}>
									Default
								</Label>
								<Input
									name={`default${ name }`}
									type='text'
									placeholder='Default'
									value={param.default}
									onChange={(e) => updateParameter(name, {
										...param,
										default: e.target.value
									})}
								/>
							</Col>
							||
							<Col sm='auto'>
								<Label>
									Default
								</Label>
								<FormGroup check>
									<Row>
										<Col>
											<Label check>
												<Input
													name={`default${ name }`}
													type='radio'
													checked={param.default && !new_param}
													value={true}
													onChange={(e) => updateParameter(name, {
														...param,
														default: true
													})}
												/>
												True
											</Label>
										</Col>
										<Col>
											<Label check className='ml-1'>
												<Input
													name={`default${ name }`}
													type='radio'
													checked={!param.default && !new_param}
													value={false}
													onChange={(e) => updateParameter(name, {
														...param,
														default: false
													})}
												/>
												False
											</Label>
										</Col>
									</Row>
								</FormGroup>
							</Col>
					}
				</FormGroup>
			</React.Fragment>
		);
	}
}
