import _ from 'lodash'
import { render } from 'preact'
import { useEffect, useState } from 'preact/hooks'
import { ToolOverlay } from './components/CourseVisibility.jsx'

import { EventsView, MODE_COURSES, MODE_SCHEDULE } from './components/EventsView.jsx'
import { HamburgerMenu } from './components/HamburgerMenu.jsx'
import { Help } from './components/Help.jsx'
import { Icon } from './components/Icon.jsx'
import { Popup } from './components/Popup.jsx'
import { Toolbar } from './components/Toolbar.jsx'
import { OptionBar } from './components/OptionBar.jsx'
import { prettyAulaName, prettyProfName, usePersistentState } from './utils.jsx'

window._ = _
window.dataBuffer = {}

const CALENDAR_IDS = {
    'anno-1': ['64a7c1c651f079001d52e9c8'],
    'anno-2': ['6308e2dc09352a0208fefdd9'],
    'anno-3': ['6308e42a1df5cb026699ced4'],
    'magistrale': ['64a7c7091ab813002c5d9ede'],
    'tutti': [
        '64a7c1c651f079001d52e9c8',
        '6308e2dc09352a0208fefdd9',
        '6308e42a1df5cb026699ced4',
        '64a7c7091ab813002c5d9ede',
    ],
}

const TIMETABLE_IDS = {
    'anno-1':     '64a7c1c651f079001d52e9c8',
    'anno-2':     '6308e2dc09352a0208fefdd9',
    'anno-3':     '6308e42a1df5cb026699ced4',
    'magistrale': '64a7c7091ab813002c5d9ede',
}

const DEFAULT_DATE_RANGE = {
    from: '2023-10-02T00:00:00.000Z',
    to: '2023-10-07T00:00:00.000Z',
}

const DATE_RANGES = {
    '64a7c1c651f079001d52e9c8': DEFAULT_DATE_RANGE,
    '6308e2dc09352a0208fefdd9': DEFAULT_DATE_RANGE,
    '6308e42a1df5cb026699ced4': DEFAULT_DATE_RANGE,
    '64a7c7091ab813002c5d9ede': DEFAULT_DATE_RANGE,
}

function specialEventPatches(eventi) {
    // Il laboratorio del primo anno in realtà è in due canali separati
    let i = 1
    eventi.forEach(evento => {
        if (evento.nome === 'LABORATORIO DI INTRODUZIONE ALLA MATEMATICA COMPUTAZIONALE') {
            evento.nome += ` (${i})`
            i++
        }
    })

    return eventi
}

function formatEvents(timetable) {
    return timetable.map(
        ({ nome, dataInizio, dataFine, docenti, aule }) => {
            return {
                id: nome,
                name: _.split(nome, '-', 1)[0].trim(),
                start: new Date(dataInizio),
                end: new Date(dataFine),
                docenti: docenti.map(({ nome, cognome }) => prettyProfName(nome, cognome)),
                aule: aule.map(aula => prettyAulaName(aula.codice)),
            }
        }
    )
}

async function loadCalendari() {
    async function req(id) {
        // Almost directly copy-pasted from Chrome Dev Tools
        const req = await fetch(
            'https://apache.prod.up.cineca.it/api/Impegni/getImpegniCalendarioPubblico',
            {
                headers: {
                    'content-type': 'application/json;charset=UTF-8',
                    'sec-fetch-dest': 'empty',
                    'sec-fetch-mode': 'cors',
                    'sec-fetch-site': 'same-site',
                },
                body: JSON.stringify({
                    mostraImpegniAnnullati: true,
                    mostraIndisponibilitaTotali: false,
                    linkCalendarioId: id,
                    clienteId: '628de8b9b63679f193b87046',
                    pianificazioneTemplate: false,
                    dataInizio: DATE_RANGES[id].from,
                    dataFine: DATE_RANGES[id].to,
                }),
                method: 'POST',
                mode: 'cors',
                credentials: 'omit',
            }
        )

        return await req.json()
    }

    const requests = [
        req(TIMETABLE_IDS['anno-1']),
        req(TIMETABLE_IDS['anno-2']),
        req(TIMETABLE_IDS['anno-3']),
        req(TIMETABLE_IDS['magistrale']),
    ]
    const results = await Promise.all(requests)
    const timetablesRaw = results.map(timetable => specialEventPatches(_.uniqBy(timetable, 'id')))
    const allRaw = specialEventPatches(_.uniqBy(_.concat(...results), 'id'))

    return {
        'anno-1':     formatEvents(timetablesRaw[0]),
        'anno-2':     formatEvents(timetablesRaw[1]),
        'anno-3':     formatEvents(timetablesRaw[2]),
        'magistrale': formatEvents(timetablesRaw[3]),
        'tutti':      formatEvents(allRaw)
    }
}

const App = ({}) => {
    // Data Sources
    const [source, setSource] = usePersistentState('orario.source', 'magistrale')
    const [timetables, setTimetables] = useState(null)
    useEffect(async () => {
        setTimetables(await loadCalendari())
    }, [])

    // View Modes
    const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES)

    // Selection
    const [selectedCourses, setSelectedCourses] = usePersistentState('orario.selection', [])

    // Menus
    const [helpVisible, setHelpVisible] = useState(false)
    const [showMobileMenu, setShowMobileMenu] = useState(false)

    // const groupIds = new Set(eventi.map(e => e.nome))
    const toolOverlayVisible = selectedCourses.length > 0

    const [theme, setTheme] = usePersistentState(
        'orario.theme',
        window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
    )

    document.body.classList.toggle('dark-mode', theme === 'dark')

    return (
        <>
            <Toolbar
                {...{
                    mode,
                    setMode,
                    source,
                    setSource,
                    onShowMenu: () => setShowMobileMenu(true),
                    onHelp: () => setHelpVisible(true),
                    theme,
                    setTheme,
                }}
            />
            {mode === MODE_COURSES && (
                <OptionBar
                    {...{
                        mode,
                        setMode,
                        source,
                        setSource,
                        onHelp: () => setHelpVisible(true),
                    }}orizzontale
                />
            )}
            {timetables && (
                <EventsView
                mode={mode}
                selection={selectedCourses}
                setSelection={setSelectedCourses}
                start={new Date(2022, 10, 3)}
                source={source}
                timetables={timetables}
                />
            )}
            {toolOverlayVisible && (
                <ToolOverlay
                    mode={mode}
                    toggleMode={() => setMode(mode === MODE_COURSES ? MODE_SCHEDULE : MODE_COURSES)}
                    onClose={() => {
                        setSelectedCourses([])
                        setMode(MODE_COURSES)
                    }}
                />
            )}
            {showMobileMenu && (
                <HamburgerMenu
                    {...{
                        mode,
                        setMode,
                        source,
                        setSource,
                        theme,
                        setTheme,
                        onClose: () => {
                            setShowMobileMenu(false)
                        },
                    }}
                />
            )}
            {helpVisible && (
                <Popup
                    title={
                        <>
                            <Icon name="info" /> Guida
                        </>
                    }
                    onClose={() => setHelpVisible(false)}
                >
                    <Help />
                </Popup>
            )}
        </>
    )
}

render(<App />, document.body)
