import { SearchResult } from '@/types/search-types'
import { getDb } from '@/utils/ContentDatabase'
import { SEARCH_RESULTS, searchBucket, sectionTypeBucket } from '@/utils/search-api'
import { NextRequest } from 'next/server'

type Data = {
	results: {
		articles: SearchResult[]
		apiDocs: SearchResult[]
		examples: SearchResult[]
	}
	status: 'success' | 'error' | 'no-query'
}

const BANNED_HEADINGS = ['new', 'constructor', 'properties', 'example', 'methods']

export async function GET(req: NextRequest) {
	const { searchParams } = new URL(req.url)
	const query = searchParams.get('q')?.toLowerCase()

	if (!query) {
		return new Response(
			JSON.stringify({
				results: structuredClone(SEARCH_RESULTS),
				status: 'no-query',
			}),
			{
				status: 400,
			}
		)
	}

	try {
		const results: Data['results'] = structuredClone(SEARCH_RESULTS)
		const db = await getDb()
		const searchForArticle = await db.db.prepare(
			`
	SELECT id, title, sectionId, categoryId, content
	FROM ftsArticles
	WHERE ftsArticles MATCH ?
	ORDER BY bm25(ftsArticles, 1000.0)
`,
			query
		)

		await searchForArticle.all().then(async (queryResults) => {
			for (const article of queryResults) {
				const section = await db.getSection(article.sectionId)
				const category = await db.getCategory(article.categoryId)
				const isUncategorized = category.id === section.id + '_ucg'

				results[searchBucket(article.sectionId)].push({
					id: article.id,
					type: 'article',
					subtitle: isUncategorized ? section.title : `${section.title} / ${category.title}`,
					title: article.title,
					sectionType: sectionTypeBucket(section.id),
					url: isUncategorized
						? `${section.id}/${article.id}`
						: `${section.id}/${category.id}/${article.id}`,
					score: 0,
				})
			}
		})

		const searchForArticleHeadings = await db.db.prepare(
			`
	SELECT id, title, articleId, slug
	FROM ftsHeadings
	WHERE ftsHeadings MATCH ?
	ORDER BY bm25(ftsHeadings, 1000.0)
`,
			query
		)

		await searchForArticleHeadings.all().then(async (queryResults) => {
			for (const heading of queryResults) {
				if (BANNED_HEADINGS.some((h) => heading.slug.endsWith(h))) continue

				const article = await db.getArticle(heading.articleId)
				const section = await db.getSection(article.sectionId)
				const category = await db.getCategory(article.categoryId)
				const isUncategorized = category.id === section.id + '_ucg'

				results[searchBucket(article.sectionId)].push({
					id: article.id + '#' + heading.slug,
					type: 'heading',
					subtitle: isUncategorized ? section.title : `${section.title} / ${category.title}`,
					sectionType: sectionTypeBucket(section.id),
					title:
						section.id === 'reference'
							? article.title + '.' + heading.title
							: article.title + ': ' + heading.title,
					url: isUncategorized
						? `${section.id}/${article.id}#${heading.slug}`
						: `${section.id}/${category.id}/${article.id}#${heading.slug}`,
					score: 0,
				})
			}
		})

		Object.keys(results).forEach((section: string) => {
			results[section as keyof Data['results']] = results[section as keyof Data['results']].slice(
				0,
				20
			)
		})

		results.articles.sort(
			(a, b) => (b.type === 'heading' ? -1 : 1) - (a.type === 'heading' ? -1 : 1)
		)

		return new Response(JSON.stringify({ results, status: 'success' }), {
			status: 200,
		})
	} catch (e: any) {
		return new Response(
			JSON.stringify({
				results: structuredClone(SEARCH_RESULTS),
				status: 'error',
				error: e.message,
			}),
			{
				status: 500,
			}
		)
	}
}
