import * as cache from "@lib/cache/cache.ts";
import * as openai from "@lib/openai.ts";
import * as tmdb from "@lib/tmdb.ts";
import { GenericResource } from "@lib/types.ts";
import { parseRating } from "@lib/helpers.ts";

type RecommendationResource = {
  id: string;
  type: string;
  rating: number;
  tags?: string[];
  description?: string;
  keywords?: string[];
  author?: string;
  year?: number;
};

export async function createRecommendationResource(
  res: GenericResource,
  description?: string,
) {
  const cacheId = `recommendations:${res.type}:${res.id.replaceAll(":", "")}`;
  const resource: RecommendationResource = await cache.get(cacheId) || {
    id: res.id,
    type: res.type,
    rating: -1,
  };
  if (description && !resource.keywords) {
    const keywords = await openai.createKeywords(res.type, description, res.id);
    if (keywords?.length) {
      resource.keywords = keywords;
    }
  }

  const { author, date, rating } = res.meta || {};

  if (res?.tags) {
    resource.tags = res.tags;
  }

  if (typeof rating !== "undefined") {
    resource.rating = parseRating(rating);
  }

  if (author) {
    resource.author = author;
  }

  if (description) {
    resource.description = description;
  }

  if (date) {
    const d = typeof date === "string" ? new Date(date) : date;
    resource.year = d.getFullYear();
  }

  cache.set(cacheId, JSON.stringify(resource));
}

export async function getRecommendation(
  id: string,
  type: string,
): Promise<RecommendationResource | null> {
  const res = await cache.get(`recommendations:${type}:${id}`) as string;
  try {
    return JSON.parse(res);
  } catch (_) {
    return null;
  }
}

export async function getSimilarMovies(id: string) {
  const recs = await getRecommendation(id, "movie");
  if (!recs?.keywords?.length) return;

  const recommendations = await openai.getMovieRecommendations(
    recs.keywords.join(),
    [recs.id],
  );
  if (!recommendations) return;

  const movies = await Promise.all(recommendations.map(async (rec) => {
    const m = await tmdb.searchMovie(rec.title, rec.year);
    return m?.results?.[0];
  }));

  return movies.filter(Boolean);
}

export async function getAllRecommendations(): Promise<
  RecommendationResource[]
> {
  const keys = await cache.keys("recommendations:movie:*");
  return Promise.all(keys.map((k) => cache.get(k))).then((res) =>
    res.map((r) => JSON.parse(r))
  );
}
