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

import { EventsView, MODE_COURSE } 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': ['6308cfcb1df5cb026699ce32'],
    'anno-2': ['63ce711cc3940409488f274e'],
    'anno-3': ['63ce736abfadbe06acc8338d'],
    'magistrale': ['63ce74397a9aee064ee01ad7'],
    'tutti': [
        '6308cfcb1df5cb026699ce32',
        '63ce711cc3940409488f274e',
        '63ce736abfadbe06acc8338d',
        '63ce74397a9aee064ee01ad7',
    ],
}

const DEFAULT_DATE_RANGE = {
    from: '2023-03-06T00:00:00.000Z',
    to: '2023-03-12T00:00:00.000Z',
}

const DATE_RANGES = {
    '6308cfcb1df5cb026699ce32': DEFAULT_DATE_RANGE,
    '63ce711cc3940409488f274e': DEFAULT_DATE_RANGE,
    '63ce736abfadbe06acc8338d': DEFAULT_DATE_RANGE,
    '63ce74397a9aee064ee01ad7': 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
}

async function loadEventi(ids) {
    const calendari = await Promise.all(
        ids.map(async 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()
        })
    )

    if (ids.length === 1) {
        return specialEventPatches(calendari[0])
    }

    return specialEventPatches(_.uniqBy(_.concat(...calendari), 'id'))
}

const App = ({}) => {
    // Data Sources
    const [source, setSource] = usePersistentState('orario.source', 'magistrale')
    const [eventi, setEventi] = useState([])

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

    // Selection
    const [selectedCourses, setSelectedCourses] = usePersistentState('orario.selection', [])
    const [hideOtherCourses, setHideOtherCourses] = usePersistentState('orario.hide-other', false)

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

    useEffect(async () => {
        const eventi = await loadEventi(CALENDAR_IDS[source])

        window.dataBuffer[source] = eventi

        setEventi(eventi)
    }, [source])

    const groupIds = new Set(eventi.map(e => e.nome))
    const toolOverlayVisible =
        selectedCourses.length > 0 && selectedCourses.filter(id => groupIds.has(id)).length > 0

    useEffect(() => {
        const groupIds = new Set(eventi.map(e => e.nome))

        if (
            selectedCourses.length === 0 ||
            (eventi.length > 0 && selectedCourses.filter(id => groupIds.has(id)).length === 0)
        ) {
            setHideOtherCourses(false)
        }
    }, [eventi, selectedCourses.length])

    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,
                }}
            />
            <OptionBar
                {...{
                    mode,
                    setMode,
                    source,
                    setSource,
                    onHelp: () => setHelpVisible(true),
                }}
            />
            <EventsView
                mode={mode}
                selection={selectedCourses}
                setSelection={setSelectedCourses}
                hideOtherCourses={hideOtherCourses}
                start={new Date(2022, 10, 3)}
                events={eventi.map(({ nome, dataInizio, dataFine, docenti, aule }) => ({
                    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)),
                }))}
            />
            {toolOverlayVisible && (
                <ToolOverlay
                    visibility={hideOtherCourses}
                    toggleVisibility={() => setHideOtherCourses(s => !s)}
                    onClose={() => {
                        setSelectedCourses([])
                        setHideOtherCourses(false)
                    }}
                />
            )}
            {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)
