import { Metadata } from "next";
import { notFound, redirect } from "next/navigation";
import { cache } from "react";
import { defineQuery } from "next-sanity";
import { sanity } from "@/lib/sanity";

import { AnimatedText } from "@/components/AnimatedText";
import { ReleaseCover } from "@/components/release/ReleaseCover";
import { StreamingLinks } from "@/components/release/StreamingLinks";
import { urlFor } from "@/lib/sanityImage";
import { ARTIST_PLACEHOLDER_SRC } from "@/lib/constants";
import { buildLinks, type Release } from "@/lib/release";

export const dynamicParams = true;
export const revalidate = 86400;

const RELEASE_BY_CATALOG_NO_QUERY = defineQuery(`
*[_type == "release" && lower(catalogNo) == $slug][0]{
  name,
  albumArtist,
  label,
  catalogNo,
  albumCover,
  officialUrl,
  spotifyUrl,
  appleMusicUrl,
  deezerUrl,
  amazonMusicUrl,
  tidalUrl,
  qobuzUrl,
}
`);

const getRelease = cache(async (slug: string) => {
  try {
    const release = await sanity.fetch<Release>(RELEASE_BY_CATALOG_NO_QUERY, { slug });
    return release;
  } catch (error) {
    console.error("Failed to fetch release:", error);
    return null;
  }
});

const RELEASE_CATALOG_SLUGS_QUERY = defineQuery(
  `*[_type == "release" && defined(catalogNo)][]{ "slug": lower(catalogNo) }`,
);

export async function generateStaticParams() {
  const releases = await sanity.fetch<{ slug: string }[]>(RELEASE_CATALOG_SLUGS_QUERY);

  return releases.map(({ slug }) => ({ slug }));
}

export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;

  if (!slug) return { title: "TRPTK" };

  const release = await getRelease(slug.toLowerCase());

  if (!release) return { title: "TRPTK" };

  const description = `Listen to ${release.name}${release.albumArtist ? ` by ${release.albumArtist}` : ""} on all major streaming platforms.`;

  const ogImage = release.albumCover
    ? urlFor(release.albumCover).width(1200).height(1200).url()
    : undefined;

  return {
    title: `${release.albumArtist ? `${release.albumArtist} • ` : ""}${release.name}`,
    description,
    openGraph: {
      title: release.name,
      description: `${release.albumArtist || "TRPTK"}${release.label ? ` - ${release.label}` : ""}`,
      type: "music.album",
      ...(ogImage && { images: [{ url: ogImage, width: 1200, height: 1200, alt: `${release.name} by ${release.albumArtist}` }] }),
    },
    twitter: {
      card: "summary_large_image",
      title: release.name,
      description,
      ...(ogImage && { images: [ogImage] }),
    },
  };
}

export default async function ReleasePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  if (!slug) notFound();

  const normalizedSlug = slug.toLowerCase();
  if (slug !== normalizedSlug) {
    redirect(`/${normalizedSlug}`);
  }

  const release = await getRelease(slug);
  if (!release) notFound();

  const links = buildLinks(release);
  const title = release.name ?? slug;
  const albumArtist = release.albumArtist ?? "";

  return (
    <div className="flex h-dvh w-full flex-col">
      <main className="mx-auto my-auto w-full max-w-90 px-6 py-12 text-center font-silka text-sm text-lighttext transition-all duration-1000 ease-in-out md:px-8 md:py-16 dark:text-darktext">
        <header>
          <ReleaseCover
            src={release.albumCover ? urlFor(release.albumCover).url() : ARTIST_PLACEHOLDER_SRC}
            alt={`Album cover image for ${title} by ${albumArtist}`}
          />

          <div className="my-10">
            <AnimatedText
              text={title}
              as="h1"
              className="mb-2 font-argesta text-2xl break-words text-lighttext dark:text-white"
            />
            <AnimatedText
              text={albumArtist}
              as="h2"
              className="text-sm break-words text-lightsec dark:text-darksec"
              delay={0.25}
            />
          </div>
        </header>

        <StreamingLinks releaseName={release.name} links={links} />
      </main>
    </div>
  );
}
