import React, { Component, useEffect } from 'react';
import * as Shared from 'placeholder-shared'
import { connect } from 'react-redux'
import * as Common from './common'
import * as Operation from './Operation'
import * as App from './App'
import * as Redux from 'redux'
import { Provider } from 'react-redux'
import Cookies from 'universal-cookie';
import * as Antd from 'antd'
import * as Tree from './Tree'

import {
	CognitoUserPool,
	CognitoUserAttribute,
	CognitoUser,
	AuthenticationDetails
} from 'amazon-cognito-identity-js';
import AWS from 'aws-sdk';
import * as AWSCognito from './Cognito';
//import { getClientType } from '../../shared/src/Common';

//*********DYNAMO START HERE**********/
/*
import initializeCognito from './initialize-cognito';
import InitializeCognito from './initialize-cognito'
const [doRegister, doVerify, doLogin, doRefresh] = initializeCognito();
const [addClientJob, listClientJob] = Shared.Dynamo.initializeDynamoDB();
*/
/************DYNAMO END HERE*********/

//import LogRocket from 'logrocket';
declare var languagePluginLoader: any;

interface Props {
	specs:any,
	currentState:any,
	requestTree:any,
	tasks:any,
	treeData:any,
	stepData:any,
	environments:any,
	currentEnvironment:any,
	currentStep:Number;
	dirty:string,
	onGotTasks?:Function,
	onRefreshComplete:Function,
	onGotRequestTree:Function,
	onGotFolders:Function,
	onGotUserInfo:Function,
	onSelectTask:Function,
	onShowStep?:Function,
	setCookieState:Function,
	setDirty?:Function,
	newAPICall?:Function,
	currentTask:Number;
	dispatch:Function;
}

interface MyState {
}

const mapPropsForLoader = (state: any, ownProps: any): any => {
	return {
		currentState: state,
		specs: state['specs'],
		requestTree: state['requestTree'],
		dirty: state['dirty'],
		tasks: state['tasks'],
		currentTask: state['currentTask'],
		treeData: state['treeData'],
		currentStep: state['currentStep'],
		stepData: state['stepsData'],
		environments: state['environments'],
		currentEnvironment: state['currentEnvironment']
	}
}


const mapDispatchForLoader = (dispatch:Function, ownProps:any): {[func: string]: Function} => {
	return  {
		dispatch,
		onGotTasks: (taskList:any) => dispatch(Shared.State.getLoadTasksAction(taskList)),
		onRefreshComplete: () => { },
		onGotRequestTree: (requestTreeJson) => {
			let requestTree = Shared.RequestTree.getRequestTreeFromJson(requestTreeJson)
			dispatch(Shared.State.getChangeRequestTree(requestTree))
		},
		onGotFolders: (folders) => {
			//dispatch(State.getUpdateFoldersTree(folders))
		},
		onGotUserInfo: (userInfo: any) => {
			//dispatch(Shared.State.getUserInfoAction(userInfo))
		},
		setDirty: () => {
			//dispatch(Shared.State.getDirtyAction(true))
		},
		onSelectTask: (taskID) => {
			dispatch(Shared.State.getLoadTaskAction(taskID))

		},
		onShowStep: (stepCounter: Number) => {
			dispatch(Shared.State.getShowStepAction(stepCounter))
		},
	}
}
export class SemanticStyle extends Component<{}, {}> {
	constructor(props: any) {
		super(props)
	}
	render() {
		return <>
			{/*}
			<link
				rel="stylesheet"
				href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"
			/>
	*/}
			<link href="https://cdn.jsdelivr.net/npm/handsontable@7.4.2/dist/handsontable.full.min.css" rel="stylesheet" media="screen" />
		</>
	}
}

enum StoreContextState {
	LoadingFromFile,
	Loaded,
}



export class StoreContext extends Component<{}, {
	loadingState: StoreContextState
}> {
	persister: Shared.Data.Persister;
	store: Redux.Store;
	emailAddr: string;
	userId: string;
	constructor(props) {
		super(props)
		this.state = { loadingState: StoreContextState.LoadingFromFile }
		this.initializeCredentials()
		.then(() => Shared.Data.getStartingState(Shared.Data.getMainFilePath()))
		.then((data) => {
			let jsonData = data
			console.log("got data read! ", jsonData)
			Shared.Data.setNextIDs(jsonData)
			jsonData = this.hydrateStoreData(jsonData)
			this.store = Shared.State.CreateStore(jsonData)
			if(!Shared.Common.isDemoEnvironment()){
				this.persister = new Shared.Data.Persister(this.store);
			}
			this.setState({ loadingState: StoreContextState.Loaded })
		}).catch((err)=>{
			//CODE HERE!
			//console.log("promise returned an error!");
			console.error(err)
			console.log("Error on login. You are about to be kicked out.")
			window.location.href = '/account/login';
			console.assert(false);
		});
		//Don't start persistor if the starting state throws error
	}
	initializeCredentials = () => {
		if (Shared.Common.IsElectron() ){
			return Promise.resolve()
		}
		return new Promise((resolve, reject) => {
			let cognitoUser = Shared.Dynamo.getCognitoUser();
			const clientType = Shared.Common.getClientType();

			if (Shared.Common.isCommandLine()) {
				console.log("detected command line, returning")
				resolve()
				return;
			}
			switch(clientType){
				case Shared.Dynamo.ClientType.client:
					AWSCognito.doRefresh((err, data)=>{
						if (err) { reject(err) }
						else {
							cognitoUser = Shared.Dynamo.getCognitoUser();
							if(cognitoUser == null){
								reject('not authenticated');
							} else {
								this.emailAddr = data.EmailAddr;
								const id_token = data.id_token;
								AWSCognito.getUserId(id_token, (err2, data2)=>{  
									if(err2){ reject(err2)}
									this.userId = data2.IdentityId;
									resolve();
								})
							}
						}
					})
					break;
				case Shared.Dynamo.ClientType.demo:
					resolve();
					break;
				case Shared.Dynamo.ClientType.sso:
					const dummyFn = ()=>{
						const access_token = Shared.Common.getHashParam("access_token");
						const id_token = Shared.Common.getHashParam("id_token");
						AWSCognito.getSsoUser(access_token, (err1, data1)=>{
							if (err1) { reject(err1) }
							this.emailAddr = data1.UserAttributes.find(attr => attr.Name == 'email').Value;
							AWSCognito.getUserId(id_token, (err2, data2)=>{  
							if(err2){ reject(err2)}
								this.userId = data2.IdentityId;
								resolve();
							})
						})
					}
					if(cognitoUser){
						AWSCognito.doLogout((err, data)=>{
							if(err) { reject(err)}
							console.log("Logged out of old cognitoUser")
							dummyFn();
						})
					} else {
						dummyFn();
					}
					break;
				default:
					console.assert(false);
			}
		})
	}
	hydrateStoreData =  (jsonData) => {
		jsonData['requestTree'] = Shared.RequestTree.getRequestTreeFromJson(jsonData['requestTree'])
		let newTreeDatas = {}
		//todo: remove object initialization logic here
		if (Shared.Common.getValueSafe(jsonData, ['treeData',1], false)){
			newTreeDatas[1] = Shared.TreeData.getTreeDataFromJson(jsonData['treeData'][1])
		}
		else{
			newTreeDatas[1] = new Shared.TreeData.TreeData()
		}
		
		jsonData['treeData'] = newTreeDatas;
		jsonData.currentTask = 1;

		//always reset offsets
		if (jsonData.UIState) {
			jsonData.UIState.TreeOffset = { x: 0, y: 0 }
			jsonData.UIState.HistoryOffset = { x: 0, y: 0 }
			jsonData.UIState.portOffset = { x: 0, y: 0 }
			jsonData.UIState.dragStep = null
			jsonData.UIState.dragOver = null
		}
		if (jsonData.sizeRegistry) {
			jsonData.sizeRegistry = {}
		}
		//Probably the wrong way to do this, but it is only used on first initialization.
		if(!jsonData.hasOwnProperty('userConfig')){
			jsonData.userConfig = {};
		}
		//I don't know if this bad practice, but this.emailAddr and this.userId
		//are assigned as undefined as a env=demo user here, doesn't cause any problems
		jsonData.userConfig.emailAddr = this.emailAddr;
		jsonData.userConfig.userId = this.userId;

		jsonData.modelViewerCurrentSteps = []
		return jsonData;
			
	}
	render() {
		switch (this.state.loadingState) {
			case StoreContextState.LoadingFromFile:
				return <div><Antd.Spin></Antd.Spin></div>
			case StoreContextState.Loaded:
				return <Provider store={this.store}>{this.props.children}</Provider>
			default:
				console.assert(false)
		}
	}
}

export class Loader extends Component<Props, MyState> {
	retrieving: boolean;
	creatingTask: boolean;
	persister: Shared.Data.Persister;
	constructor(props: any) {
		super(props)
		this.retrieving = false
		this.creatingTask = false;
	}
	componentDidUpdate() {

	}

	getTasks = () => {
		return Shared.Utils.apiGet("getTasks", {}).then((taskList) => {
			//this.props.onGotTasks!(taskList)	
		})
	}
	getSimulations = () => {
		return Shared.Utils.apiGet("getSimulations", {}).then((simulations) => {
			//this.props.onGotSimulations!(simulations)	
		})
	}
	getRequestTree = () => {
		//return Shared.GetState.GetRequestTree().then((result) => {
		//this.props.onGotRequestTree(result)
		//})
	}
	getFolders = () => {
		//return Shared.GetState.GetFolders().then((result) => {
		//this.props.onGotFolders(result)
		//})
	}
	getUserInfo = () => {
		return Shared.Utils.apiGet("userInfo", {}).then((userInfo) => {
			this.props.onGotUserInfo!(userInfo);
			//LogRocket.identify(userInfo.username, {})
		})
		// Add your own custom user variables here, ie:
		//   subscriptionType: 'pro'
		//   });
		/*
		eval('Intercom')('update', {
			user_id:userInfo.username,
			app_id:'waqlpiuw'
		})
		*/
	}
	componentWillMount() {
		if (!Object.keys(this.props.tasks).length) {
			this.props.dispatch(Shared.State.getCreateTaskAction(1, 'Task 1'))
			this.props.onSelectTask(1)
		}

	}
	componentDidMount() {

			/*
		//add first request
			let newNodeAdded = Tree.AddNewNode(this.props.currentState, this.props.requestTree, null,
				Shared.RequestTree.RequestNodeType.task)
			this.props.onSelectTask(newNodeAdded.nodeID)
			this.props.onShowStep(newNodeAdded.nodeID)
		}
		return;
		/*
		console.log("loading specs")
		console.assert(this.props.dirty) 
		this.retrieving = true
		var updates:Promise<any>[] = []
		updates.push(Shared.Specs.loadSpecs(this.props.specs, 0 , true).then(this.loadedSpecInfo))
		updates.push(this.getTasks())
		updates.push(Shared.GetState.GetRunResultsHistory())
		updates.push(this.getSimulations())
		updates.push(Shared.GetState.GetRequestTree())
		updates.push(Shared.GetState.GetFolders())
		updates.push(this.getUserInfo())

		Promise.all(updates).then((values) => {
			this.retrieving = false
			let runResults = values[2]
			let simulations = values[3]
			let requestTree = values[4]
			let folders = values[5]
			//this.props.onGotRequestTree(requestTree)
			//this.props.onGotFolders(folders)
			//this.props.onGotRunResultsHistory(runResults)
			this.props.onRefreshComplete()
		})
		*/
	}

	render() {
		return <>

			<SemanticStyle> </SemanticStyle>
		</>
	}
}
export const StateLoader: any = connect(mapPropsForLoader, mapDispatchForLoader)(Loader as any)

export const UserLoader = (props: {}) => {
	useEffect(() => {
		console.log("hi")
	}, [])

	return null;
}
