/* eslint-disable react/display-name */
import React , {Suspense,useMemo, useRef, useEffect, useCallback,useState} from 'react';
import { shallowEqual, connect ,useSelector,useDispatch,batch} from 'react-redux';
import {Button, Segment} from 'semantic-ui-react'
import * as Common from './common'
import * as Lineage from './Lineage'
import * as SC from './SComponents'
import * as Immer from 'immer'
import * as Steps from './Steps2'
import './StepMenu.scss'
import * as TaskHeader from './TaskHeader'
import * as Shared from 'placeholder-shared'
import * as Data from './Data'
import * as Antd from 'antd'
import * as LoadSourceTable from './LoadSourceTable'
import * as Materialization from './Materialization'
import { AutoSizer } from 'react-virtualized'
import * as Icon  from '@ant-design/compatible';

import MonacoEditor from 'react-monaco-editor'
import {
	MenuFoldOutlined,
	MenuUnfoldOutlined,
	FormatPainterOutlined,
	PartitionOutlined,
	PlayCircleOutlined,
	DownOutlined,
	AimOutlined,
	InfoCircleOutlined
  } from '@ant-design/icons'
import ReactResizeDetector from 'react-resize-detector';
/*
import  AceEditor from 'react-ace'
import "ace-builds/src-noconflict/mode-sql";
*/

interface Cell {
	row: number; col: number;
}
interface Selection {
	start: Cell,
	end: Cell
}

export const useViewDependencies = () => {
	const dispatch = useDispatch()
	return useCallback((stepCounter:number) => {
		dispatch((dispatch, getState) => {
			batch(() => {
				if (getState().currentStep && getState().edges.gFinal){
					const predecessors = getState().edges.gFinal.predecessors(getState().currentStep).map(s => `dependency-${parseInt(s)}`)
					dispatch(Shared.State.changeModelViewerState(stepCounter,'expandedKeys', ['Dependencies']))
					dispatch(Shared.State.changeModelViewerState(stepCounter,'selectedKeys', predecessors))
				}
				else {
					Antd.message.error(
						'No step selected. Unable to show dependencies.'
					)

				}
			})
		})
	}, [dispatch ])
}
export const useChangeTab = () => {
	const dispatch = useDispatch()
	return useCallback(() => {
		dispatch((dispatch, getState) => {
			if (getState().UIState.mainWindowActiveTab == 'modelViewer') {
				dispatch(Shared.State.changeUIState('mainWindowActiveTab', 'graph'))
				return;
			}
			batch(() => {
				dispatch(Shared.State.changeUIState('mainWindowActiveTab', 'modelViewer'))
			})
		})
	}, [dispatch])
}

export const useGetSteps = () => {
	const lineageGroups = useSelector(state=> (state as any).lineageGroups)
	return useCallback(() => {
		let steps = {}
	
		Object.keys(lineageGroups).map((l) => {
			if (lineageGroups[l].show) {
				Object.keys(Shared.Common.getValueSafe(lineageGroups, [l,'steps'], {})).forEach((s) => {
					steps[parseInt(s)] = true
				})
			}
		}
		)
		return steps;
	},[lineageGroups])
}

export const useGetFiltering = () => {
	const lineageGroups = useSelector(state=> (state as any).lineageGroups)
	return useMemo(() => {
		return !lineageGroups? [] : Object.keys(lineageGroups).map((l) => {
			return lineageGroups[l].show? l: null
		}).filter(s => s!= null)
	}, [lineageGroups])
}

export const useSourceAlreadyExists = () => {
	const getStepsCB = useGetSteps()
	const nameAlreadyExistsCB = useNameAlreadyExistsCB()

	const steps = useSelector(state => (state as any).steps)
	const lineageGroups = useSelector(state=> (state as any).lineageGroups)

	const filtering = useGetFiltering()
	return useCallback((sourceName)=> {
		if (!filtering.length) {
			return nameAlreadyExistsCB(0, sourceName)
		}
		const stepsDict = getStepsCB()
		let found = false
		let conflicting = null;
		Object.keys(stepsDict).forEach((s) => {
			const stepCounter = parseInt(s)
			if (steps[stepCounter].operation.type == Shared.Runner.StepTypes.sourceInput) {
				if (steps[stepCounter].operation.table.toUpperCase() == sourceName.toUpperCase())
					found = true;
				conflicting = steps[stepCounter].operation.table
			}
		})
		return [found, conflicting]
	},[getStepsCB,steps,lineageGroups,nameAlreadyExistsCB,filtering])
}

export const useNameAlreadyExistsCB = () => {
	const stepCounter = useSelector(state => (state as any).currentStep)
	const steps = useSelector(state => (state as any).steps)
	const treeData = useSelector(state => (state as any).treeData[1])
	return useCallback((excludeStepCounter,name) => {
		let ret = [false,null, null]
		if (!name){
			return ret
		}
		Shared.TreeData.forAllStepsInTask(treeData, steps, (stepCounter, stepData) => {
			if (stepCounter == excludeStepCounter){
				return  //dont check if you are already using the name
			}
			let stepName = null
			if (stepData.operation.type == Shared.Runner.StepTypes.sourceInput) {
				stepName = stepData.operation.table
			}
			else {
				stepName = stepData.operation.name
			}
			if (stepName.toUpperCase() == name.toUpperCase()) {
				ret = [true, stepName, stepCounter]
			}
		})
		return ret
	},[steps,treeData])
}
export const StepMonitor = (props:{})=> {
	const steps = useSelector (state => (state as any).steps)
	const treeData = useSelector (state => (state as any).treeData[1])
	const dispatch = useDispatch()
	useEffect(() => {
		const lineageGroups = {}
		for (let s in treeData.nodes) {
			const node = treeData.nodes[s]
			const operation = steps[node.stepCounter].operation
			if (typeof operation.lineageGroup == 'object') {
				Object.keys(operation.lineageGroup).forEach((l) => {
					if (!(l in lineageGroups)){
						lineageGroups[l] = {}
					}
					lineageGroups[l][node.stepCounter] = true
				})
			}
		}
		dispatch(Shared.State.updateLineageGroups(lineageGroups))
	},[steps,dispatch,treeData.nodes])

	const materializations = useSelector(state => (state as any).materializations)
	useEffect(() => {
		Object.keys(materializations).forEach((mCounter) => {
			Shared.Materialization.processMaterializationString(materializations[mCounter].code).then((ret)=>{
				//handlers might have an error field in it 
				dispatch(Shared.State.UpdateMaterializationAction(parseInt(mCounter), ret))
			})
		})
	}, [dispatch, materializations])

	return <>
	<Lineage.CreateLineageModal/>
	</>;
}

export const useLoadSourceTableModalStatus = () => {
	const stepCounter = useSelector(state => (state as any).currentStep)
	const stepData = useSelector(state => (state as any).steps[stepCounter])
	const loadSourceTableModalActivated = useMemo(()=>{
		if (stepData && stepData.operation.type == Shared.Runner.StepTypes.sourceInput &&
			(
				!stepData.operation.dataset ||
				!stepData.operation.table
			)) {
			return true;
		}
		return false;
	},[stepData])
	return loadSourceTableModalActivated 
}


export const useChangeUIState = (defaultValue: any, uiStateKey: string) => {
	const value = useSelector((currentState) => (currentState as any).UIState[uiStateKey])
    const dispatch = useDispatch()
    let cb = useCallback((value: any) => {
        dispatch(Shared.State.changeUIState(uiStateKey,
            value))
    }, [dispatch,uiStateKey])
	return [value ? value : defaultValue, cb];
}

export const useGetStepRunState = (stepCounter: number) => {
	const currentTask = useSelector(state => (state as any).currentTask)

	const stepData = useSelector(state => (state as any).steps[stepCounter])
	const runResult = useSelector(state => (state as any).runResults[stepCounter])
	const operation = useSelector(state => (state as any).steps[stepCounter].operation)
	return {
		currentTask, stepData, runResult, operation
	}
}

export const StepMenu  = (props:{})  => {
	const stepCounter = useSelector(state => (state as any).currentStep)
	const stepData = useSelector(state => (state as any).steps[stepCounter])
	const loadSourceTableModalActivated =  useLoadSourceTableModalStatus()
	if (!stepCounter || !stepData)
		return <Antd.Button><MenuFoldOutlined/> </Antd.Button>;
	let getMenu = () => {
		const type = stepData.operation.type
		const stepMenu = Steps.StepDict[type].stepMenu()
		if (!stepMenu) {
			return null;
		}
		return <Common.DivWithClassName key={stepCounter} className={
			Common.classNames({
				flexGrow:true, columnFlexBox:true,
				stepMenuFocusActivated:loadSourceTableModalActivated
			})}
			>
			<Common.DivWithClassName style={{}} className='StepMenuParent flexGrow mainPadding columnFlexBox'>
				{stepMenu}
			</Common.DivWithClassName>
			<RunPanel/>
		</Common.DivWithClassName>
	};
	return <>
		{getMenu()}
	</>
}


const SourceTableAlert = (props) => {
	const dispatch = useDispatch()
	const currentStep = useSelector(state=> (state as any).currentStep)
	const escapeListener = useCallback((ev: any) => {
		if (ev.key == 'Escape') {
			dispatch(Shared.State.getRemoveStepAction(currentStep, 1, null))
		}
	}, [dispatch,currentStep])
	useEffect(() => {
		window.addEventListener('keyup', escapeListener, false)

		return () => {
			window.removeEventListener('keyup', escapeListener, false)
		}
	})
	const onCancel = (e) => {
	}
	const onConfirm= (e) => {
		dispatch(Shared.State.getRemoveStepAction(currentStep, 1, null))
	}
	return <><Antd.Alert message={<span>
		<Antd.Typography.Text>Select a source table or </Antd.Typography.Text> 
	<SC.SPopConfirm onCancel={onCancel} onConfirm={onConfirm} text='Cancel' prompt={'Are you sure?'} />
	</span>
	}
	 type='info'>
	</Antd.Alert>
	</>
}

export const parseSourceOperation = (serializedSourceStr)=>{
	const [database, dataset, table] = serializedSourceStr.split("-")
	return {database, dataset, table};
}

export const StateSourceStepMenu = (props: {}) => {
	const dispatch = useDispatch()
	const nameAlreadyExistsCB = useNameAlreadyExistsCB()
	const stepCounter = useSelector(state => (state as any).currentStep)
	const operation:Shared.Runner.SourceOperation = useSelector(state => (state as any).steps[stepCounter].operation)
	const loadSourceTableModalStatus = useLoadSourceTableModalStatus()

	const onSelect = (keys, e) => {
		const [database, dataset, table] = keys[0].split("-")
		const [nameExists, conflictingName] = nameAlreadyExistsCB(stepCounter, table)
		if (nameExists) {
			Antd.message.error(<span>Cannot add  <b>{table}</b> because the table name {conflictingName} already exists in the graph.</span>
			)
		}
		else {
			if (database && dataset && table) {
				dispatch(Shared.State.getUpdateStepOperationAction(stepCounter,
					'database', database, false))
				dispatch(Shared.State.getUpdateStepOperationAction(stepCounter,
					'dataset', dataset, false))
				dispatch(Shared.State.getUpdateStepOperationAction(stepCounter,
					'table', table, false))
				dispatch(Shared.Runner.runStep(stepCounter))
			}
		}
	}
    const treeData = useSelector(state => (state as any).treeData[1])
	const steps= useSelector(state => (state as any).steps)
	
	const onKeyUp = (e)=> {
		console.log("on key up", e)
		debugger;


	}
	return <><Common.DivWithClassName onKeyUp={onKeyUp} className='positionRelative flexGrow overflowYScroll'>
		<Common.DivWithClassName className='padding5px columnFlexBox justifyContentCenter'>
			{loadSourceTableModalStatus && 
			<SourceTableAlert/>
			}
		</Common.DivWithClassName>
		<Common.DivWithClassName className='positionAbsolute width100Percent'>
			<LoadSourceTable.SourceTables stepCounter={stepCounter} onSelect={onSelect} />
		</Common.DivWithClassName>
	</Common.DivWithClassName>
		</>
}

export const StepMenus = (props: {}) => {
	const currentTask = useSelector(state => (state as any).currentTask)
	const currentStep = useSelector(state => (state as any).currentStep)
	const currentStepData = useSelector(state => (state as any).steps[currentStep])
	const tree:Shared.TreeData.TreeData = useSelector(state => (state as any).treeData[currentTask])

	if (!currentTask || !currentStepData) {
		return null;
	}
	return <Common.DivWithClassName className=''>
		{tree.nodes.map((treeNode:Shared.TreeData.TreeNode) => {
			return <StepMenu key={treeNode.stepCounter}  />
		})}
	</Common.DivWithClassName>
}
export var StateStepMenu = StepMenu;

const RunButton = (props: { }) => {
	const dispatch = useDispatch()
	const currentStep = useSelector(state => (state as any).currentStep)
	return <Antd.Button icon={<PlayCircleOutlined />} className='marginLeft30px' onClick={(e: React.MouseEvent) => {
		dispatch(Shared.Runner.runStep(currentStep))
	}}
		type="primary" htmlType="submit">Run</Antd.Button>
}


export const useGetMenu = () => {
	const currentStep = useSelector(state => (state as any).currentStep)
	const materializationOptions = Materialization.useMaterializationOptions()
	const dispatch = useDispatch()
	const cb = useCallback(() => {
		const handleClick = (e: any) => {
			dispatch(Shared.State.getUpdateStepOperationAction(currentStep, 'sqlType', e.key, false))
		}
		return <Antd.Menu>
			<Antd.Menu.Item key='View' onClick={handleClick}>Create View</Antd.Menu.Item>
			<Antd.Menu.Item key='Table' onClick={handleClick}>Create Table</Antd.Menu.Item>
			{/*<Antd.Menu.Item key='Incremental' onClick={handleClick}>Create Incremental</Antd.Menu.Item>*/}
			{materializationOptions}
		</Antd.Menu>
	}, [currentStep, dispatch, materializationOptions])
	return cb;
}

export const useMaterializationButtons= () => {
	const getMenu = useGetMenu()
	const currentStep = useSelector(state => (state as any).currentStep)
	const currentStepData = useSelector(state => (state as any).steps[currentStep])
	const dispatch = useDispatch()
	const docString = Materialization.useDocStringForMaterialization()
	const handlers = Materialization.useHandlersForMaterialization()
	const runMaterialization= (handlerName) => {
		console.log("running handler", handlerName)
			dispatch(Shared.Runner.runStep(currentStep, handlerName))
	}
	const getSecondAction = useCallback(()=> {
		const sqlType = currentStepData.operation.sqlType
		if (sqlType == 'View' ||
			sqlType == 'Table'
		) {
			return null;
		}
		else if (parseInt(sqlType)) {
			return Object.keys(handlers).length >= 1 && Object.keys(handlers).slice(1).map(handlerName => {
				return <Antd.Button onClick={(e) => {runMaterialization(handlerName)}} key={handlerName}>{handlerName}</Antd.Button>
			})
		}
	},[currentStepData, handlers,runMaterialization])

	const dropdown = useMemo(() => {
		return <><Antd.Dropdown.Button overlay={getMenu()} style={{ marginLeft: '5px' }} type='primary' icon={<DownOutlined />} className='marginLeft5px' onClick={(e: React.MouseEvent) => {
			dispatch(Shared.SqlTabActions.setSelfThunk()) // set to show step data
			dispatch(Shared.Runner.runStep(currentStep,'default'))
		}}>
			{!handlers && currentStepData.operation.sqlType == 'View' && 'Create View'}
			{!handlers && currentStepData.operation.sqlType == 'Table' && 'Create Table'}
			{handlers && Object.keys(handlers)[0]}
		</Antd.Dropdown.Button>
			{handlers && getSecondAction()}
			{docString &&
				<Antd.Tooltip className='paddingLeft5px' title={<span>{docString}</span>}>
					<InfoCircleOutlined />
				</Antd.Tooltip>
			}
		</>
	}, [currentStep, currentStepData, dispatch, getMenu, handlers, docString,getSecondAction])
	return dropdown;
}

export const RunPanel = (props : {}) => {
	const dispatch = useDispatch()
	const currentStep = useSelector(state => (state as any).currentStep)
	const currentStepData = useSelector(state => (state as any).steps[currentStep])
	const runResult = useSelector(state => (state as any).runResults[currentStep])
	const materializationOptions = Materialization.useMaterializationOptions()
	const materializationHandlers = Materialization.useHandlersForMaterialization()
	const materializationButtons = useMaterializationButtons()

	const getMenu = useCallback(() => {

		const handleClick = (e: any) => {
			dispatch(Shared.State.getUpdateStepOperationAction(currentStep, 'sqlType', e.key, false))
		}
		return <Antd.Menu>
			<Antd.Menu.Item key='View' onClick={handleClick}>Create View</Antd.Menu.Item>
			<Antd.Menu.Item key='Table' onClick={handleClick}>Create Table</Antd.Menu.Item>
			<Antd.Menu.Item key='Incremental' onClick={handleClick}>Create Incremental</Antd.Menu.Item>
			{materializationOptions}
		</Antd.Menu>
	},[currentStep,dispatch,materializationOptions])

	const getPreviewButton = useCallback(() => {
		return <Antd.Button type='default' icon={<AimOutlined />} className='marginLeft30px' onClick={(e: React.MouseEvent) => {
			dispatch(Shared.Runner.runStepPreview(currentStep));
		}}
			htmlType="submit">Preview</Antd.Button>
	},[currentStep,dispatch])
	const getButtons = useCallback(() => {
		if (currentStepData.operation.type == 'sourceInput') {
			return getPreviewButton();
		}
		else if (parseInt(currentStepData.operation.sqlType)) {
			return <>{getPreviewButton()}
			{materializationButtons}
			</>
		}
		else {
			return <>
			{getPreviewButton()}
			{materializationButtons}
			{/*
				<Antd.Dropdown.Button overlay={getMenu()}style={{marginLeft:'5px'}} type='primary' icon={<DownOutlined />} className='marginLeft5px' onClick={(e: React.MouseEvent) => {
					dispatch(Shared.SqlTabActions.setSelfThunk()) // set to show step data
					dispatch(Shared.Runner.runStep(currentStep))
				}}
					htmlType="submit">
						{currentStepData.operation.sqlType == 'View' && 'Create View'}
						{currentStepData.operation.sqlType == 'Table' && 'Create Table'}
						{currentStepData.operation.sqlType == 'Incremental' && 'Run Incremental'}
						</Antd.Dropdown.Button>
						*/}
			
			</>
		}
	},[getPreviewButton,currentStepData, materializationButtons])
	const errorMessage = () => {
		if (!runResult) {
			return null;
		}
		else if (runResult.editResult && runResult.editResult.error){
			return runResult.editResult.error.message
		}
		else if (runResult.previewResult && runResult.previewResult.error) {
			return runResult.previewResult.error.message
		}
		else if (runResult.createResult && runResult.createResult.error){
			return runResult.createResult.error.message
		}
		else {
			return null;
		}
	}
	const errorMessageToUse = errorMessage()
	return <Common.DivWithClassName className='alignItemsFlexStart RunPanelContainer topBorderLightGray'>
		<ErrorMessage errorMessageToUse={errorMessageToUse} />
		<Common.DivWithClassName className='marginRight10px flexGrow alignItemsFlexStart'>
			{getButtons()}
		</Common.DivWithClassName>
	</Common.DivWithClassName>
}
export const MenuLabel = (props: { className?:string,children: string | React.ReactNode }) => {
	const {className} = props;
	return <SC.SLabel className={Common.classNames({
		'menuLabelFont':true,  'font9':true, [className]:className})}>{props.children}</SC.SLabel>
}
export const TransformList = (props:{})=> {
	const currentStep = useSelector(state => (state as any).currentStep)
	const steps = useSelector(state=> (state as any).steps)
	//const operation:Shared.Runner.SelectOperation = useSelector(state => (state as any).steps[currentStep].operation)
	return <Antd.List>
		{/*joperation.transforms.map((t,index) => {
			return <Antd.List.Item key={index}>
				{steps[t].operation.type}
			</Antd.List.Item> 
		})*/}
	</Antd.List>
}

export const SuccessMessage = (props:{successMessage}) => {
	const {successMessage} = props
	return <Common.DivWithClassName className='errorMessage'>
		{successMessage &&
			<Antd.Typography.Text className='textGreen' style={{ fontSize: 10 }} type='secondary'>{successMessage}</Antd.Typography.Text>
		}
	</Common.DivWithClassName>
}
export const ErrorMessage = (props:{errorMessageToUse}) => {
	const {errorMessageToUse} = props
	return <Common.DivWithClassName className='errorMessage'>
		{errorMessageToUse &&
			<Antd.Typography.Text style={{ fontSize: 10 }} type='danger'>{errorMessageToUse}</Antd.Typography.Text>
		}
	</Common.DivWithClassName>
}

export const FormatButton = (props: { onClick: any; text: string }) => {
	const { text, onClick } = props
	return < Antd.Button onClick={onClick} className='' type='default' size='small' >
		<FormatPainterOutlined />{text}
	</Antd.Button >
}
