import { useEffect, useRef, useState } from 'preact/hooks'

import _ from 'lodash'
import { differenceInMinutes, startOfDay } from 'date-fns'

import { hashString, normalizeCourseName, WEEK_DAYS } from '../../utils.jsx'
import { layoutIntervals } from '../../interval-layout.js'

export const WorkWeekGrid = ({ events, selection, setSelection, hideOtherCourses }) => {
    const selectionSet = new Set(selection)

	const colorList = [
		'red',
		'purple',
		'blue',
		'yellow',
		'green',
		'orange',
		'lightblue',
	];

	const courses = _.uniqBy(!hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)), event => event.id);
	const colors = Object.fromEntries(courses.map((course, index) => {
		return [
			course.id,
			[
				colorList[index % colorList.length],
				courses.length <= colorList.length ? '' : String.fromCharCode(65 + Math.floor(index / colorList.length))
			]
		];
	}));

	const base = {
		1: [],
		2: [],
		3: [],
		4: [],
		5: [],
	}
    const eventsByWeekday = {
		... base,
		... _.groupBy(
        !hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)),
        event => event.start.getDay()
    	)
	}

    const dayIntervalLayout = _.mapValues(eventsByWeekday, events =>
        layoutIntervals(
            events.map(e => ({
                start: differenceInMinutes(e.start, startOfDay(e.start)),
                end: differenceInMinutes(e.end, startOfDay(e.start)),
                data: e,
            }))
        )
    )
	const startsAndEnds = Object.entries(dayIntervalLayout).flatMap(([index, layout]) => layout.flatMap(events => events.map(event => [event.start, event.end])));
	const minStart = Math.min(...startsAndEnds.map(([s, e]) => s)) / 60;
	const maxEnd = Math.max(...startsAndEnds.map(([s, e]) => e)) / 60;
	// const timeStart =   minStart < 9 ? 7 :
	// 					minStart < 11 ? 9 :
	// 					minStart < 13 ? 11 :
	// 					minStart < 14 ? 13 :
	// 					minStart < 16 ? 14 :
	// 					minStart < 18 ? 16 : 
	// 					18;
	// const timeEnd = maxEnd > 18 ? 20 :
	// 				maxEnd > 16 ? 18 :
	// 				maxEnd > 14 ? 16 :
	// 				maxEnd > 13 ? 14 :
	// 				maxEnd > 11 ? 13 :
	// 				maxEnd > 9 ? 11 :
	// 				9;
	const timeStart =   minStart < 9 ? 7 : 9;
	const timeEnd = maxEnd > 18 ? 20 : 18;


	const daySizes = Object.entries(dayIntervalLayout).map(([index, layout]) => Math.max(1, layout.length));
	const dayOffsets = daySizes.map((v, i) => {
		let sum = 0;
		for(let j = 0; j < i; j++) {
			sum += daySizes[j];
		}
		return sum;
	});
	const daysLength = daySizes[4] + dayOffsets[4];

    const [currentlyHovered, setCurrentlyHovered] = useState(null)
    const element = useRef()

    useEffect(() => {
        if (element.current) {
            const l = e => {
                const $event = e.target.closest('.event')
                if ($event) {
                    setCurrentlyHovered($event.dataset.eventId)
                } else {
                    setCurrentlyHovered(null)
                }
            }

            element.current.addEventListener('mousemove', l)
            element.current.addEventListener('mouseleave', l)

            return () => {
                element.current.removeEventListener('mousemove', l)
                element.current.removeEventListener('mouseleave', l)
            }
        }
    }, [element.current])

    return (
        <div class="work-week-grid-view" ref={element}>
			<div class="grid" style={{'--days-length': daysLength, '--time-length': timeEnd - timeStart}}>
				{[7, 9, 11, 14, 16, 18].map(n => 
					<>
						{n + 2 > timeStart && n < timeEnd && (
							<div class="time" style={{'--offset': n - timeStart + 2}}>{n}-{n+2}</div>
						)}
					</>
				)}
				<div class="vline" style="--offset: 2"></div>
				{[9, 11, 13, 14, 16, 18].map(n => 
					<>
						{n > timeStart && n < timeEnd && (
							<div class="vline" style={{'--offset': n - timeStart + 2}}></div>
						)}
					</>
				)}

				<div class="day-name" style={{'--line': 2 + dayOffsets[0]}}>Lun</div>
				<div class="day-name" style={{'--line': 2 + dayOffsets[1]}}>Mar</div>
				<div class="day-name" style={{'--line': 2 + dayOffsets[2]}}>Mer</div>
				<div class="day-name" style={{'--line': 2 + dayOffsets[3]}}>Gio</div>
				<div class="day-name" style={{'--line': 2 + dayOffsets[4]}}>Ven</div>

				<div class="hline" style={{'--line': 2 + dayOffsets[0]}}></div>
				<div class="hline" style={{'--line': 2 + dayOffsets[1]}}></div>
				<div class="hline" style={{'--line': 2 + dayOffsets[2]}}></div>
				<div class="hline" style={{'--line': 2 + dayOffsets[3]}}></div>
				<div class="hline" style={{'--line': 2 + dayOffsets[4]}}></div>

				{Object.entries(dayIntervalLayout).map(([index, layout]) => (
					<>
						{layout.map((events, stackIndex) => (
							<>
								{events.map(event => (
									<div class={
											'event' +
											(currentlyHovered === event.data.id
												? ' highlight'
												: '') +
											(selectionSet.has(event.data.id) ? ' selected' : '')
										}
                                        data-event-id={event.data.id}
										style={{
											'--line': 2 + dayOffsets[index-1] + stackIndex,
											'--offset': event.start / 60  - timeStart + 2,
											'--length': (event.end - event.start) / 60,
											'--color': `var(--bubble-${colors[event.data.id][0]})`,
											'--border-color': `var(--bubble-border-${colors[event.data.id][0]})`,
											'--highlight-color': `var(--bubble-highlight-${colors[event.data.id][0]})`
										}}
                                        onClick={() => {
                                            if (!selectionSet.has(event.data.id))
                                                setSelection([...selection, event.data.id])
                                            else
                                                setSelection(
                                                    selection.filter(id => event.data.id !== id)
                                                )
                                        }}
									>
										{colors[event.data.id][1] !== '' && (
											<div className="distinguisher">{`(${colors[event.data.id][1]})`}</div>
										)}
										{event.data.aula}</div>
								))}
							</>
						))}
					</>
				))}
			</div>
			<div class="legend">
				{courses.map(course => (
					<>
						<div class="color" 
							style={{
								'--color': `var(--bubble-${colors[course.id][0]})`,
								'--border-color': `var(--bubble-border-${colors[course.id][0]})`
							}}
						>
							{colors[course.id][1]}
						</div>
						<div class="name">{normalizeCourseName(course.name)}</div>
					</>
				))}
			</div>
        </div>
    )
}
