import * as React from 'react';
import { MessageType } from '@theia/core';
import { Flex, Box } from '@rebass/grid';

import CatalogoSearchHeader from './main/catalogo-search-header';
import CatalogoConnectors from './main/catalogo-connectors';
import ConnectorRenderer from './connectors/connectors-renderer';
import CatalogoFilters from './main/catalogo-filters';

import * as RecursiveIterator from 'recursive-iterator';
import setNested from '../../common/utils/set-nested-key';

import { ContainerContext } from './catalogo-context';

import { IConnectorConfig, IStepConnectorForm, IConnectorData } from '../../common/catalogo-protocol';
import { icon as iconDefault } from '../../common/mock/mock-connectors';

import { Empty, Typography, Button } from 'antd';
const { Title } = Typography;

interface CatalogoLayoutProps {
	
}

interface CatalogoLayoutState {
	connectors: IConnectorConfig[]; // lista de conectores
	steps: IStepConnectorForm[]; // lista de passos do formulário para instalação do conector
	selectedConnector: number; // Connector selecionado. Pode ser por seleção do usuario ou por que ele já tem dado registrado
	module_installed: any;
	loadingConnectors: boolean; //true quando estiver carregando a lista de conectores
	filterName: string; // Palavra chave para busca
	filterCategories: string[]; // Categorias para filtrar conectores
	editingConnectorData: IConnectorData; // Foi encontrado dados referente ao connector e entra no modo edição
	error: string; // error do componente contendo a mensagem
}

class CatalogoLayout extends React.Component<CatalogoLayoutProps, CatalogoLayoutState> {
	static contextType = ContainerContext;
	context!: React.ContextType<typeof ContainerContext>;
		 
	constructor(props: any) {
		super(props);

		this.state = {
			connectors: [],
			steps: [],
			selectedConnector: -1,
			module_installed: '',
			filterName: '',
			loadingConnectors: false,
			filterCategories: [],
			editingConnectorData: {version: null, type: null, image: null},
			error: null
		}
	}

	async componentDidMount() {
		if(this.context.service) {
			const connectors = this.context.service.getConnectors();

			this.setState({connectors}, async () => {
				try {
					const json = await this.context.resource.readContents();
					const content: Object = JSON.parse(json === '' ? '{}' : json);
					const type: string = content['type'];
	
					if(type) {
						const selectedConnector =
							connectors.reduce((prev, curr, index) =>{
								return curr.type === type ? index : prev;
							}, -1);
						
						if(selectedConnector > -1) {
							// Força seleção do connector
							this._handlerSelect(selectedConnector, content);
						} else {
							this.context.service.logMessage({type: MessageType.Error, text: 'Connector Type not Found!'});
						}
					}
	
				} catch (err) {
					console.error(err);
					this.context.service.logMessage({type: MessageType.Error, text: 'Error when trying read content .connector file'});
				}
			});
		}
	}

	componentDidUpdate() {
		
	}

	// Handle do botão de reload dos connectores
	private reloadConnectors = async () => {
		this.setState({ loadingConnectors: true });
		const connectors = await this.context.service.reloadConnectors();

		this.setState({ connectors, loadingConnectors: false });
	}

	/**
	 * Verifica se o connector possui imagem. Caso não possua utiliza uma imagem default
	 * para exibição no overview 
	*/
	private verifyConnectorImage = (connector: IConnectorConfig) => {
		const hasImageConnector = connector.image && (connector.image !== null || connector.image !== '');

		return hasImageConnector ? connector.image : iconDefault;
	}

	/**
	 * Verifica se existe um usuário criador ou uma organização que fez o connector.
	 * Caso exista monta o overview para exibir essa informação
	 */
	private verifyAuthors = (connector: IConnectorConfig) => {
		const hasUserCreator = connector.userCreator && (connector.userCreator !== null || connector.userCreator !== '');
		const hasOrganizationCreator = connector.organizationCreator && (connector.organizationCreator !== null || connector.organizationCreator !== '');
		return hasUserCreator
				? connector.userCreator
				: hasOrganizationCreator
					? connector.organizationCreator
					: ''
	}

	private defaultValues = (steps: IStepConnectorForm[], content: Object) => {
		const withValues = steps.slice(1);

		return withValues.map(step => {
			const withDefaults = Object.assign({}, step.content.metadata.data);

			for(let {key, path} of new RecursiveIterator(step.content.metadata.data)) {
				if(key === 'default') {
					setNested(path.join('.'), content[path[path.length - 2]], withDefaults);
				}
			}

			return {
				...step,
				content: {
					...step.content,
					metadata: {
						...step.content.metadata,
						data: withDefaults
					}
				}
			}
		});
	}

	private enrichSteps = (connector: IConnectorConfig, steps: IStepConnectorForm[], connectorContent: Object) => {
		return [
			{
				...steps[0],
				version: connector.version,
				image: this.verifyConnectorImage(connector),
				author: this.verifyAuthors(connector)
			},
			...(connectorContent ? this.defaultValues(steps, connectorContent) : steps.splice(1))
		];
	}

	// Seleçaõ de um connector
	private _handlerSelect = (connIndex: number, content?: Object) => {
		const steps = this.context.service.getConnectorForm(this.state.connectors[connIndex].type);

		if(steps) {
			const enriched = this.enrichSteps(this.state.connectors[connIndex], steps, content);

			this.setState(
				{
					selectedConnector: connIndex,
					steps: enriched,
					editingConnectorData: {version: null, type: null, image: null, ...content}
				}
			);
		} else {
			this.context.service.logMessage({type: MessageType.Error, text: 'Connector Form not Found'});
		}
		
	}

	private _handlerBack = () => this.setState({selectedConnector: -1, editingConnectorData: {version: null, type: null, image: null}});

	// Mudando a busca por texto
	private _handlerChange = (value: string) => this.setState({filterName: value});
	
	// Ao selecionar uma categoria para filtro
	private _handleChangeCategories = (categories: string[]) => this.setState({filterCategories: categories});

	// private _installModule = () => {}

	render() {
		const {
			connectors,
			selectedConnector,
			filterName,
			filterCategories,
			error,
			loadingConnectors,
			editingConnectorData
		} = this.state;

		if(error) return <Title type={"danger"}>{error}</Title>

		return (
			<Box>
				{
					selectedConnector === -1
						? <Flex p={`1rem`} flexDirection="column" justifyContent="center">
							<Flex mb={'10px'} flexDirection="row" justifyContent="space-between">
								<CatalogoSearchHeader onChange={(value) => this._handlerChange(value)}/>
								<Button
									title="Refresh Marketplace List"
									shape="circle" icon="sync" size="large"
									loading={loadingConnectors}
									onClick={() => this.reloadConnectors()}
								/>
							</Flex>
								<CatalogoFilters onChange={(categories) => this._handleChangeCategories(categories)} connectors={connectors}/>
							<Box mt={'5px'}>
								{
									connectors.length > 0
										? <CatalogoConnectors
											connectors={connectors}
											onSelect={(connIndex) => this._handlerSelect(connIndex)}
											filters={{name: filterName, category: filterCategories}}
										/>
										: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>
								}
								
							</Box>
						</Flex>
						: <Flex>
							<ConnectorRenderer 
								onBack={() => this._handlerBack()}
								editingData={editingConnectorData}
								connector={connectors[selectedConnector]}
								steps={this.state.steps}
							/>
						</Flex>
				}
			</Box>
		);
	}
}

export default CatalogoLayout;
