// @flow
import * as React from 'react';
import {
	Container,
	Row,
	Col,
	TabContent,
	TabPane,
	Nav,
	NavItem,
	NavLink,
	Input,
	InputGroupAddon,
	InputGroup,
} from 'reactstrap';

import { connect } from 'react-redux';

import cn from 'classnames';

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

import {
	Route,
	Link
} from 'react-router-dom';

import type { BeatObject, BeatEntity } from '@helpers/beat';
import { getDefaultEntityObject, pluralize } from '@helpers/beat';
import { genModuleApiFuncs } from '@helpers/api';
import ValidSchemaBadge from './ValidSchemaBadge.jsx';

import DataformatEditorContainer from './dataformat';
import AlgorithmEditorContainer from './algorithm';
import LibraryEditorContainer from './library';
import DatabaseEditorContainer from './database';
import ExperimentEditorContainer from './experiment';
import ToolchainEditorContainer from './toolchain';
import PlotterEditorContainer from './plotter';
import PlotterparameterEditorContainer from './plotterparameter';

type Props = {
	// the match object from react-router
	// used to find which object to render
	match: any,
	// the history object from react-router
	// used to push new history to
	history: any,
	// gets the object based on the current URL
	getEntityObject: () => BeatObject,
	// gets the object's index # in the Redux array based on the current URL
	getEntityIndex: () => number,
	// updates the current object
	updateFunc: (BeatObject) => any,
	// the current BEAT entity being show
	entity: BeatEntity,
	// the absolute path to the user's prefix folder
	prefix: string,
};

// 3 tabs so far: editor, docs, raw json
type Tab = '0' | '1' | '2';

type State = {
	// which tab is active
	activeTab: Tab,
};

// wrapper for editors
// doesnt really do much now besides the raw json tab
export class EntityDetail extends React.Component<Props, State> {
	constructor(props: Props){
		super(props);
	}

	state = {
		activeTab: '0',
	}

	switchToTab = (tab: Tab) => {
		this.setState({
			activeTab: tab
		});
	}

	saveChanges = (newObj: BeatObject) => {
		this.props.updateFunc(newObj);
		const put = genModuleApiFuncs(this.props.entity).put;
		return put([newObj]);
	}

	render () {
		const name = this.props.match.params.name;
		const obj = this.props.getEntityObject();
		const index = this.props.getEntityIndex();
		let expName;
		if(this.props.entity === 'experiment'){
			const segs = name.split('/');
			const usern = segs.shift();
			const expn = segs.pop();
			const tcn = segs.join('/');
			expName = <span>{ usern }/<Link to={`/toolchain/${ tcn }`}>{ tcn }</Link>/{ expn }</span>
		}
		return (
			<Container>
				<Row className='mb-1'>
					<Col>
						{/* title line (name & validation info) */}
						<h4 className='text-center'>
							<span style={{'textTransform': 'capitalize'}}>
								{ this.props.entity }
							</span>
							{' '}
							<pre style={{display: 'inline'}}>
								{ expName || name }
							</pre>
							<ValidSchemaBadge entity={this.props.entity} obj={obj} />
						</h4>
						{/* path line */}
						<InputGroup>
							<InputGroupAddon addonType='prepend'>Path:</InputGroupAddon>
							<Input
								readOnly
								width='80'
								value={`${ this.props.prefix }/${ pluralize(this.props.entity) }/${ name }`}
							/>
						</InputGroup>
					</Col>
				</Row>
				<Row>
					<Col sm='12'>
						<Nav tabs className='nav-fill'>
							<NavItem>
								<NavLink
									className={cn({ active: this.state.activeTab === '0' })}
									onClick={() => this.switchToTab('0')}
								>
									Editor
								</NavLink>
							</NavItem>
							<NavItem>
								<NavLink
									className={cn({ active: this.state.activeTab === '1' })}
									onClick={() => this.switchToTab('1')}
								>
									Raw JSON
								</NavLink>
							</NavItem>
						</Nav>
						<TabContent activeTab={this.state.activeTab} className='mt-2'>
							{/* Uses the appropriate editor, could probably be done nicer */}
							<TabPane tabId='0'>
								{
									this.props.entity === 'algorithm' &&
										<AlgorithmEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'dataformat' &&
										<DataformatEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'library' &&
										<LibraryEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'database' &&
										<DatabaseEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'experiment' &&
										<ExperimentEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'toolchain' &&
										<ToolchainEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'plotter' &&
										<PlotterEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
								{
									this.props.entity === 'plotterparameter' &&
										<PlotterparameterEditorContainer
											saveFunc={this.saveChanges}
											index={index}
										/>
								}
							</TabPane>
							<TabPane tabId='1'>
								<pre>{ JSON.stringify(obj, null, 4) }</pre>
							</TabPane>
						</TabContent>
					</Col>
				</Row>
			</Container>
		);
	}
}

const mapStateToProps = (state, ownProps) => {
	// which beat entity is currently active: 'algorithm', 'plotter', 'database', etc.
	const entity = ownProps.match.params.entity;
	// the name of the object ("atnt/1", "plot/isoroc/1", "user/tc/test/1/exp", etc.)
	const name = ownProps.match.params.name;
	const obj = {
		// uses a selector based off the entity and finds the obj given the name
		// if the obj doesnt exist (huge edge case) just return a default obj to not break everything
		getEntityObject: (): BeatObject => Selectors[`${ entity }Get`](state).find(o => o.name === name) || getDefaultEntityObject(),
		getEntityIndex: (): number => Selectors[`${ entity }Get`](state).findIndex(o => o.name === name),
		entity,
		prefix: Selectors.settingsGet(state).prefix,
	};

	return obj;
};

const mapDispatchToProps = (dispatch, ownProps) => ({
	// replace the obj in the Redux store with the new object
	updateFunc: (obj) => {
		dispatch(Actions[`${ ownProps.match.params.entity }Update`](ownProps.match.params.name, obj));
		ownProps.history.push(`/${ ownProps.match.params.entity }/${ obj.name }`);
	},
});

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