import React, { useState } from 'react';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import TableSortLabel from '@mui/material/TableSortLabel';
import Paper from '@mui/material/Paper';
import classNames from 'classnames';
import Button from "@mui/material/Button";
import { visuallyHidden } from '@mui/utils';
import _ from 'lodash';
import Box from "@mui/material/Box";

// let columns = [
// 	{
// 		name: "ID",
// 		value: (row) => row._id,
//      descendingComparator: (a, b) => {return value(b) < value(a) ? 1 : value(b) > value(a) ? -1 : 0}
// 	}
// ]
//
// let rows = [
// 	{
// 		_id: 1234,
// 		name: "abc",
// 		value: 123
// 	}
// ]
//
// let options = {
// 	key: (row) => row._id,
// 	editor: (row) => {return (<MyRowEditor value={row}/>)}
//  add: true,
//  maxHeight: "40rem",
//  remove: (row) => { /* show dialog and/or perform remove */ }
// }

const cssTopControls = {
	display: 'flex',
	flexDirection: 'row',
	justifyContent: 'flex-end',
}

/*
 * Separate the Meteor calls as much as possible to avoid them being run repeatedly unnecessarily (were being run on every selection in the table).
 */
export default ({columns, rows, options}) => {
	const [selected, setSelected] = useState(undefined);

	let selectRow = (e, row) => {
		setSelected(row);
	}

	const [edited, setEdited] = useState(undefined);
	const [order, setOrder] = useState('asc')  //'asc' or 'desc'
	const [orderBy, setOrderBy] = useState(undefined);  //Column name being sorted.

	let editRow = (e, row) => {
		setEdited(row);
	}
	
	const closeEditor = () => {
		setEdited(undefined)
	}
	
	const addRow = () => {
		setEdited({});
	}
	
	let containerStyle = options.maxHeight ? {maxHeight: options.maxHeight} : {}
	let keyHandler = (e) => {
		!edited && options.keyHandler && options.keyHandler(e, selected)
		
		// Close the editor if the user hits escape.
		if(edited && e.key === 'Escape') {
			setEdited(undefined)
			e.stopPropagation()
		}
		
		if(!edited && e.key === 'Insert') {
			setEdited({})
			e.stopPropagation()
		}
		
		if(!edited && e.key === 'Delete' && selected && options.delete && _.isFunction(options.delete)) {
			options.delete(selected)
		}
	}
	
	const sort = (e, column) => {
		const isAscending = orderBy === column && order === 'asc'  //Descending if this is the first click on the column or toggling from ascending.
		setOrder(isAscending ? 'desc' : 'asc')
		setOrderBy(column)
	}

	const descendingComparator = (a, b, orderBy) => {
		let av = orderBy.value(a)
		let bv = orderBy.value(b)
		
		if(bv < av) return -1
		else if(bv > av) return 1
		else return 0
	}
	const getComparator = (order, orderBy) => {
		if(!orderBy) return undefined
		else if(orderBy.descendingComparator) return order === 'desc' ? (a,b) => orderBy.descendingComparator(a,b) : (a,b) => -orderBy.descendingComparator(a,b)
		else return order === 'desc'
			? (a, b) => descendingComparator(a, b, orderBy)
			: (a, b) => -descendingComparator(a, b, orderBy);
	}
	const stableSort = (array, comparator) => {
		if(comparator) {
			const stabilizedThis = array.map((el, index) => [el, index]);
			stabilizedThis.sort((a, b) => {
				const order = comparator(a[0], b[0]);
				if (order !== 0) {
					return order;
				}
				return a[1] - b[1];
			});
			return stabilizedThis.map((el) => el[0]);
		}
		else return array
	}
	// console.log(rows)
	return (
		<div className='simpleTableContainer'>
			<div style={cssTopControls}>
				{options.add && <Button variant="text" className="button" onClick={addRow}>Add</Button>}
				{options.remove && _.isFunction(options.remove) && <Button disabled={!selected} variant='text' className='button' onClick={() => {selected && options.remove(selected)}}>Remove</Button>}
			</div>
			<TableContainer className="simpleTable" component={Paper} style={containerStyle}>
				<Table size="small" aria-label="Table" tabIndex="0" onKeyDown={keyHandler}>
					<TableHead className="sticky">
						<TableRow>
							{columns.map((column, i) => {return (
								<TableCell key={i} className="headerCell" sortDirection={orderBy === column ? order : false}>
									<TableSortLabel active={orderBy === column} direction={orderBy === column ? order : 'asc'} onClick={(e) => {sort(e, column)}}>
										{column.name}
										{orderBy === column.name && (
											<Box style={{color: 'white'}} component="span" sx={visuallyHidden}>
												{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
											</Box>
										)}
									</TableSortLabel>
								</TableCell>
							)})}
						</TableRow>
					</TableHead>
					<TableBody>
						{edited && !options.key(edited) && (
							<TableRow key="NewEditor" className="tableRow">
								<TableCell className="editorContainer" colSpan={columns.length}>
									{options.editor(edited, closeEditor)}
								</TableCell>
							</TableRow>
						)}
						{stableSort(rows, getComparator(order, orderBy)).map((row, i) => {
							return (
								<TableRow key={options.key(row)} className={classNames({tableRow: true, selected: (!edited || options.key(edited) !== options.key(row)) && selected && options.key(selected) === options.key(row)})} onDoubleClick={(e) => {editRow(e, row)}} onClick={(e) => selectRow(e, row)}>
									{edited && options.key(edited) === options.key(row) ?
										<TableCell className="editorContainer" colSpan={columns.length}>
											{options.editor(edited, closeEditor)}
										</TableCell>
										:
										<>
											{columns.map((column, ci) => {
												// console.log("Rendering Cell")
												// console.log(column);
												// console.log(column.value(row));
												let value = column.value(row);
												
												if(_.isObject(value)) {
													console.error("Cannot have an object returned as the value in a table.")
													console.log("Cell value: ")
													console.log(value)
													value = JSON.stringify(value)
												}
												
												return (
													<TableCell key={ci} align="left">{value}</TableCell>
												)
											})}
										</>
									}
								</TableRow>
							)
						})}
					</TableBody>
				</Table>
			</TableContainer>
		</div>
	)
}