import React from 'react';
import FontFaceObserver from 'fontfaceobserver';
import FilterSidebar from './filter-sidebar.component';
import ConnectionMap from './map/connection-map.class';
import './scss/main.scss';
import cloneDeep from 'lodash/cloneDeep';
import { getAvailableFilters, getDataTree, IAvailableFilters } from './data';
import RootCompany from './root-company.component';

export type ExternalAction = (scoutId: string) => void;

export interface ExternalActions {
	onNavigateToConnectionMap: ExternalAction;
	onNavigateToCompanyPage: ExternalAction;
	onViewCompany: ExternalAction;
	onViewLatestNews: ExternalAction;
	onAddToTargetList: ExternalAction;
	onBackAction?: () => void;
}

export interface IConnectionScoutCompanyData {
	[x: string]: any;
	scoutId: string;
}

export interface IConnectionCompanyData {
	entityId: string;
	parentEntityId: string;
	ultimateParentId: string;
	name: string;
	isScoutCompany: boolean;
	country: string;
	country_iso3: string;
	company?: IConnectionScoutCompanyData;
	subsidiaryCount?: number;
	directSubsidiaryCount?: number;
	parent?: IConnectionCompanyData;
	subsidiaries?: Array<IConnectionCompanyData>;
	active?: boolean;
	node?: any;
	link?: any;
}

interface IConnectionMapComponentProps extends ExternalActions {
	connectionsData: Array<IConnectionCompanyData>;
	requestId: string;
}

interface IConnectionMapComponentState {
	didError: boolean;
	processedConnectionsData?: IConnectionCompanyData;
	renderMap: boolean;
	availableFilters: IAvailableFilters;
}

export default class ConnectionMapComponent extends React.Component<
	IConnectionMapComponentProps,
	IConnectionMapComponentState
> {
	node: SVGSVGElement;
	connectionMap: ConnectionMap;

	state = {
		didError: false,
		processedConnectionsData: null,
		renderMap: false,
		availableFilters: {
			countries: []
		}
	};

	componentDidMount() {
		const { connectionsData, requestId } = this.props;

		let processedConnectionsData;
		let availableFilters;

		try {
			const clonedData = cloneDeep(connectionsData);
			availableFilters = getAvailableFilters(connectionsData);
			processedConnectionsData = getDataTree(clonedData, requestId);

			this.setState(
				{
					processedConnectionsData,
					availableFilters,
					renderMap: true
				},
				() => {
					this.connectionMap = new ConnectionMap(this.node);
					this.connectionMap.bindConnectionMapNavigationEventToNodes(
						this.props.onNavigateToConnectionMap
					);
					this.connectionMap.bindCompanyPageNavigationEventToNodes(
						this.props.onNavigateToCompanyPage
					);
					this.connectionMap.bindCompanyViewEventToNodes(
						this.props.onViewCompany
					);
					this.connectionMap.bindLatestNewsViewEventToNodes(
						this.props.onViewLatestNews
					);
					this.connectionMap.bindAddToTargetListNavigationEventToNodes(
						this.props.onAddToTargetList
					);
					this.forceUpdate(); // ensure that filter bar picks up the connection map prop
				}
			);

			try {
				const font = new FontFaceObserver('MetricWeb', {
					weight: 400
				});

				font.load().then(
					() => {
						this.connectionMap.render(processedConnectionsData);
					},
					() => {
						console.log('Font is not available');
						this.connectionMap.render(processedConnectionsData);
					}
				);
			} catch (error) {
				if (console && console.error)
					console.error('Error in connection map rendering');
				this.componentDidCatch(error);
			}
		} catch (err) {
			if (console && console.error)
				console.error(
					'Error in connection map data processing',
					err,
					processedConnectionsData
				);
			this.componentDidCatch(err);
		}
	}

	componentDidCatch(error: Error) {
		this.setState(oldState => ({
			didError: true
		}));

		if (console && console.error) console.error(error);
	}

	componentDidUpdate() {
		if (this.connectionMap) this.connectionMap.updateNode(this.node);
	}

	render() {
		const { processedConnectionsData } = this.state;

		if (this.state.didError) {
			return (
				<div className="map map--error">
					<span className="map--error-msg">
						Oops, the connection map can't be displayed as an error
						occurred, please try again later.
					</span>
				</div>
			);
		}

		return (
			<div className="connection-map">
				<div className="connection-map__content">
					<div className="connection-map__map-container">
						<FilterSidebar
							map={this.connectionMap}
							availableFilters={this.state.availableFilters}
							onBackAction={this.props.onBackAction}
						/>

						<div className="connection-map__root">
							<RootCompany
								company={processedConnectionsData}
								main
								{...this.props}
							/>

							{processedConnectionsData
								? (() => {
										const output = [];
										let company = processedConnectionsData;
										while (company.parent) {
											output.push(
												<RootCompany
													key={
														company.parent.entityId
													}
													company={company.parent}
													collapsible={true}
													parent
													{...this.props}
												/>
											);
											company = company.parent;
										}

										return output.length ? (
											<div className="connection-map__parents">
												{output}
											</div>
										) : null;
								  })()
								: null}
						</div>

						{this.state.renderMap ? (
							<div className="connection-map__map">
								<div className="connection-map__map-scroll">
									<svg
										className="connection-map__svg"
										ref={node => (this.node = node)}
									/>
								</div>
							</div>
						) : null}
					</div>
				</div>
			</div>
		);
	}
}
