import { Comic, ComicBubble, ComicPage } from "@prisma/client";
import { Hit, SearchResponse } from "meilisearch";
import { GetServerSideProps } from "next";
import Head from "next/head";
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
import { useEffect, useState } from "react";
import { LinkButton } from "../../../components/Button";
import HighlightComic from "../../../components/HighlightComic";
import TextInput from "../../../components/TextInput";
import { prisma } from "../../../src/db";
import { searchClient } from "../../../src/search";

interface Params extends ParsedUrlQuery {
    comic: string;
}

interface Props {
    initialSearchQuery: string;
    comic: Comic;
}

type ComicPageResult = { id: string; } & Omit<ComicPage, 'id'> & {
    comic: Comic;
    bubbles: ComicBubble[];
}

export default function Search(props: Props) {
    const router = useRouter();

    const [searchQuery, setSearchQuery] = useState(props.initialSearchQuery);
    const [results, setResults] = useState<SearchResponse<ComicPageResult>>();
    const [selected, setSelected] = useState(-1);

    useEffect(() => {
        setSearchQuery((Array.isArray(router.query.search) ? router.query.search[0] : router.query.search) || '');
    }, [router.query]);

    useEffect(() => {
        searchClient.index('comic_pages').search<ComicPageResult>(searchQuery, {
            attributesToHighlight: ['*'],
            filter: [
                `comic.id=${props.comic.id}`,
            ],
        }).then(results => {
                setResults(results);
            });
    }, [searchQuery]);

    return <main className='p-4'>
        <Head>
            <title>Search {props.comic.title}</title>
        </Head>

        <div className='w-full flex flex-col items-center justify-center'>
            <TextInput multiline={false} value={searchQuery} onChange={(e) => {
                router.replace({
                    pathname: `/comic/${props.comic.slug}/search`,
                    query: {
                        search: e.target.value
                    },
                }, undefined, {
                    shallow: true,
                });
                setSearchQuery(e.target.value);
                setSelected(-1);
            }} placeholder='Type to search...' className='w-full max-w-xl' />
        </div>

        {results && <div className='flex flex-row w-full gap-4 justify-center pt-4'>
            <section className={'max-w-1/2 ' + (selected === -1 && 'min-w-xl')}>
                <p>
                    <i>~{results.estimatedTotalHits} total results</i>
                </p>

                <ul>
                    {results.hits.map((result, i) => {
                        return <li key={result.id}>
                            <div>
                                <h2>
                                    <LinkButton href={{
                                        pathname: `/comic/${props.comic.slug}/highlight/${result.id.split('-')[1]}`,
                                        query: {
                                            highlightedBubbles: findHighlighedBubbles(result),
                                        },
                                    }} target='_blank' onClick={(e) => {
                                        e.preventDefault();
                                        setSelected(i === selected ? -1 : i);
                                    }}>
                                        {result.title}
                                    </LinkButton>
                                </h2>
                            </div>
                        </li>
                    })}
                </ul>
            </section>
            {selected !== -1 && results.hits[selected] && <section className='max-w-1/2'>
                <h2>{results.hits[selected].title}</h2>

                <HighlightComic page={{
                    ...results.hits[selected],
                    id: parseInt(results.hits[selected].id.split('-')[1]),
                }} highlightedBubbles={findHighlighedBubbles(results.hits[selected])} />
            </section>}
        </div>}
    </main>
}

export const getServerSideProps: GetServerSideProps<Props, Params> = async ({ params, query }) => {
    const { comic: comicId } = params!;

    const comic = await prisma.comic.findFirst({
        where: {
            slug: comicId,
        },
    });

    if (!comic) return { notFound: true };

    const search = (Array.isArray(query.search) ? query.search[0] : query.search) || '';
    return {
        props: {
            initialSearchQuery: search,
            comic,
        },
    }
}

function findHighlighedBubbles(result: Hit<ComicPageResult>) {
    return result.bubbles.filter((bubble, i) => {
        if (!result._formatted?.bubbles) throw new Error();
        const fmt = result._formatted?.bubbles[i].content;
        return fmt !== bubble.content;
    }).map(bubble => bubble.idx);
}
