<script lang="ts">
    import SpaceCard from "$lib/components/SpaceCard.svelte";
    import defaultImg from "$lib/assets/study_space.png";
    import crossUrl from "$lib/assets/cross.svg";
    import searchUrl from "$lib/assets/search.svg";
    import Navbar from "$lib/components/Navbar.svelte";
    import { collectTimings, timeToMins, haversineDistance } from "$lib";
    import Button from "$lib/components/Button.svelte";
    import { urldecodeSortFilter } from "$lib/filter.js";
    import { invalidateAll } from "$app/navigation";
    import type { Table } from "$lib";

    const { data } = $props();
    const {
        studySpaces,
        supabase,
        session,
        adminMode,
        searchParams,
        favouriteIds: initialFavourites = []
    } = $derived(data);

    let favouriteIds = $derived<string[]>(initialFavourites);
    let showFavourites = $state(false);

    const sortFilter = $derived(urldecodeSortFilter(searchParams));
    const selectedTags = $derived(sortFilter.tags ?? []);
    const openingFilter = $derived(sortFilter.openAt?.from);
    const closingFilter = $derived(sortFilter.openAt?.to);
    const sortNear = $derived(sortFilter.nearby);

    // Toggle a space in/out of favourites
    async function handleToggleFavourite(id: string) {
        if (!session?.user) return;
        const already = favouriteIds.includes(id);
        if (already) {
            await supabase
                .from("favourite_study_spaces")
                .delete()
                .match({ user_id: session.user.id, study_space_id: id });
            favouriteIds = favouriteIds.filter((x) => x !== id);
        } else {
            await supabase
                .from("favourite_study_spaces")
                .insert([{ user_id: session.user.id, study_space_id: id }]);
            favouriteIds = [...favouriteIds, id];
        }
    }

    // Combine tag and time filtering
    let filteredStudySpaces = $derived(
        studySpaces
            // only include favourites when showFavourites===true
            .filter((space) => !showFavourites || favouriteIds?.includes(space.id))
            // tag filtering
            .filter((space) => {
                if (selectedTags.length === 0) return true;
                const allTags = [
                    ...(space.tags || []),
                    space.volume,
                    space.wifi,
                    space.power
                ].filter(Boolean);
                return selectedTags.every((tag) => allTags.includes(tag));
            })
            // opening time filter
            .filter((space) => {
                if (!openingFilter) return true;
                const entry = space.study_space_hours?.find(
                    (h) => h.day_of_week === new Date().getDay()
                );
                if (!entry) return false;
                if (entry.open_today_status) return true;
                const openMin = timeToMins(entry.opens_at);
                let closeMin = timeToMins(entry.closes_at);
                // Treat midnight as end of day and handle overnight spans
                if (closeMin === 0) closeMin = 24 * 60;
                if (closeMin <= openMin) closeMin += 24 * 60;
                const filterMin = timeToMins(openingFilter);
                // Include spaces open at the filter time
                return filterMin >= openMin && filterMin < closeMin;
            })
            // closing time filter
            .filter((space) => {
                if (!closingFilter) return true;
                const entry = space.study_space_hours?.find(
                    (h) => h.day_of_week === new Date().getDay()
                );
                if (!entry) return false;
                if (entry.open_today_status) return true;
                const openMin = timeToMins(entry.opens_at);
                let closeMin = timeToMins(entry.closes_at);
                if (closeMin === 0) closeMin = 24 * 60;
                if (closeMin <= openMin) closeMin += 24 * 60;
                const filterMin =
                    timeToMins(closingFilter) === 0 ? 24 * 60 : timeToMins(closingFilter);
                // Include spaces still open at the filter time
                return filterMin > openMin && filterMin <= closeMin;
            })
    );

    const sortedByOpenNow = $derived(
        filteredStudySpaces.toSorted((a, b) => {
            const now = new Date();
            const time = now.toTimeString().slice(0, 5);
            const today = now.getDay();
            let openUntil = [0, 0] as number[];
            for (const [index, day] of [a, b].entries()) {
                const timingsPerDay = collectTimings(day.study_space_hours);
                for (const timing of timingsPerDay[today]) {
                    if (timing.open_today_status === true) {
                        openUntil[index] = 24 * 60;
                        break;
                    } else if (timing.open_today_status === false) {
                        break;
                    } else {
                        const opensFor = timeUntilClosing(timing.opens_at, timing.closes_at, time);
                        if (opensFor) {
                            openUntil[index] = opensFor;
                            break;
                        }
                    }
                }
            }
            return openUntil[1] - openUntil[0];
        })
    );

    const sortedStudySpaces = $derived(
        sortNear
            ? filteredStudySpaces.toSorted((a, b) => {
                  if (!sortNear) return 0;
                  type DBLatLng = { lat: number; lng: number } | undefined;
                  const aLoc = a.building_location as unknown as google.maps.places.PlaceResult;
                  const bLoc = b.building_location as unknown as google.maps.places.PlaceResult;
                  const aLatLng = aLoc.geometry?.location as DBLatLng;
                  const bLatLng = bLoc.geometry?.location as DBLatLng;
                  const aDistance = haversineDistance(
                      sortNear.lat,
                      sortNear.lng,
                      aLatLng?.lat || sortNear.lat,
                      aLatLng?.lng || sortNear.lng
                  );
                  const bDistance = haversineDistance(
                      sortNear.lat,
                      sortNear.lng,
                      bLatLng?.lat || sortNear.lat,
                      bLatLng?.lng || sortNear.lng
                  );
                  return aDistance - bDistance;
              })
            : sortedByOpenNow
    );

    // Open now
    function isOpenNow(all_study_space_hours: Table<"study_space_hours">[]) {
        const now = new Date();
        const time = now.toTimeString().slice(0, 5);
        const day = now.getDay();

        const timingsPerDay = collectTimings(all_study_space_hours);
        for (const timing of timingsPerDay[day]) {
            if (timing.open_today_status === true) {
                return { isOpen: true, message: `Open all day` };
            } else if (timing.open_today_status === false) {
                return { isOpen: false, message: `Closed today` };
            } else {
                const opensFor = timeUntilClosing(timing.opens_at, timing.closes_at, time);
                if (opensFor) {
                    return {
                        isOpen: true,
                        message: `Open now for: ${minsToReadableHours(opensFor)}`
                    };
                }
            }
        }

        return { isOpen: false, message: "Closed right now" };
    }

    function timeUntilClosing(openingTime: string, closingTime: string, currentTime: string) {
        const currTimeInMins = timeToMins(currentTime);
        const OpeningTimeInMins = timeToMins(openingTime);
        const closingTimeInMins = timeToMins(closingTime);
        if (currTimeInMins >= OpeningTimeInMins && currTimeInMins < closingTimeInMins) {
            return closingTimeInMins - currTimeInMins;
        }
    }

    function minsToReadableHours(mins: number) {
        return `${Math.floor(mins / 60)} hrs, ${mins % 60} mins`;
    }
</script>

<Navbar>
    {#if session}
        <a href="/space/new/edit">
            <img src={crossUrl} alt="new" class="new-space" />
        </a>
    {/if}
    {#if adminMode}
        <span class="checkReports">
            <Button href="/space/reports" type="link" style="red">Check Reports</Button>
        </span>
    {/if}
    {#if session}
        <button class="fav-button" onclick={() => (showFavourites = !showFavourites)} type="button">
            {showFavourites ? "All spaces" : "My favourites"}
        </button>
    {/if}

    <div class="filterWrapper">
        <Button type="link" href="/filter?{searchParams}">
            <span class="search">
                <img src={searchUrl} alt="search" />
                Search
            </span>
        </Button>
    </div>
</Navbar>

<main>
    {#each sortedStudySpaces as studySpace (studySpace.id)}
        {@const imgUrl =
            studySpace.study_space_images.length > 0
                ? supabase.storage
                      .from("files_bucket")
                      .getPublicUrl(studySpace.study_space_images[0].image_path).data.publicUrl
                : defaultImg}
        <SpaceCard
            alt="Photo of {studySpace.description}"
            href="/space/{studySpace.id}"
            imgSrc={imgUrl}
            space={studySpace}
            isFavourite={favouriteIds.includes(studySpace.id)}
            onToggleFavourite={session ? () => handleToggleFavourite(studySpace.id) : undefined}
            isAvailable={studySpace.study_space_hours.length === 0
                ? undefined
                : isOpenNow(studySpace.study_space_hours).isOpen}
            footer={studySpace.study_space_hours.length === 0
                ? undefined
                : isOpenNow(studySpace.study_space_hours).message}
        />
    {/each}
</main>

<footer>
    {#if session}
        <Button
            onclick={async () => {
                await supabase.auth.signOut();
                invalidateAll();
            }}>Signout</Button
        >
    {:else}
        <Button href="/auth" type="link">Login / Signup</Button>
    {/if}
</footer>

<style>
    main {
        display: grid;
        box-sizing: border-box;
        grid-template-columns: 1fr 1fr;
        gap: 0.5rem;
        padding: 0.5rem;
        max-width: 32rem;
        width: 100%;
        margin: 0 auto;
    }

    footer {
        display: flex;
        flex-direction: column;
        max-width: 600px;
        width: 100%;
        padding: 1rem;
        margin: 0 auto;
    }

    .new-space {
        transform: rotate(45deg);
    }

    .checkReports {
        grid-column: 1 / -1;
        display: flex;
        flex-direction: column;
        font-size: 1rem;
        margin-left: 0.5rem;
    }

    .fav-button {
        background: none;
        border: none;
        color: #eaffeb;
        font-size: 1rem;
        cursor: pointer;
    }
    .fav-button:hover {
        text-decoration: underline;
    }

    .filterWrapper {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-right: 0.5rem;
    }

    .search {
        display: flex;
        align-items: center;
        gap: 0.3rem;
        color: #eaffeb;
        font-size: 1rem;
    }

    .search img {
        width: 1.2rem;
        height: 1.2rem;
    }

    @media (max-width: 20rem) {
        main {
            grid-template-columns: 1fr;
        }
    }
</style>
