import { BadRequestError } from "@lib/errors.ts";
import { resources } from "@lib/resources.ts";
import { SearchResult } from "@lib/types.ts";
import { getTypeSenseClient } from "@lib/typesense.ts";
import { extractHashTags } from "@lib/string.ts";

type ResourceType = keyof typeof resources;

type SearchParams = {
  q: string;
  type?: ResourceType;
  tags?: string[];
  rating?: string;
  author?: string;
  query_by?: string;
};

export function parseResourceUrl(_url: string): SearchParams | undefined {
  try {
    const url = new URL(_url);
    let query = url.searchParams.get("q") || "*";
    if (!query) {
      return undefined;
    }
    query = decodeURIComponent(query);

    const hashTags = extractHashTags(query);

    for (const tag of hashTags) {
      query = query.replace("#" + tag, "");
    }

    return {
      q: query,
      type: url.searchParams.get("type") as ResourceType || undefined,
      tags: hashTags,
      rating: url.searchParams.get("rating") || undefined,
      query_by: url.searchParams.get("query_by") || undefined,
    };
  } catch (_err) {
    return undefined;
  }
}

export async function searchResource(
  { q, query_by = "name,description,author,tags", tags = [], type, rating }:
    SearchParams,
): Promise<SearchResult> {
  const typesenseClient = await getTypeSenseClient();
  if (!typesenseClient) {
    throw new Error("Query not available");
  }

  const filter_by: string[] = [];

  if (type) {
    filter_by.push(`type:=${type}`);
  }

  if (tags?.length) {
    filter_by.push(`tags:[${tags.map((t) => `\`${t}\``).join(",")}]`);
    for (const tag of tags) {
      q = q.replaceAll(`#${tag}`, "");
    }
    if (!q.trim().length) {
      q = "*";
    }
  }

  if (typeof rating !== "undefined") {
    if (rating === "null") {
      filter_by.push(`rating: null`);
    } else {
      filter_by.push(`rating: ${rating}`);
    }
  }

  return await typesenseClient.collections("resources")
    .documents().search({
      q,
      query_by,
      facet_by: "rating,author,tags",
      max_facet_values: 10,
      filter_by: filter_by.join(" && "),
      per_page: 50,
    });
}
