import type { Metadata } from "next";
import { defineQuery } from "next-sanity";
import { sanity } from "@/lib/sanity";
import { ReleaseCard, type ReleaseCardData } from "@/components/release/ReleaseCard";
import { AnimatedText } from "@/components/AnimatedText";
import { SearchBar } from "@/components/SearchBar";
import { PaginationNav } from "@/components/PaginationNav";
import { CARD_GRID_CLASSES_4 } from "@/lib/constants";
import { PAGE_SIZE, clampInt, normalizeQuery, groqLikeParam } from "@/lib/listHelpers";
import type { SortOption } from "@/components/SortDropdown";
import type { FilterGroup } from "@/components/FilterDropdown";

export const revalidate = 86400;

type SortMode =
  | "titleAsc"
  | "titleDesc"
  | "catalogNoAsc"
  | "catalogNoDesc"
  | "releaseDateAsc"
  | "releaseDateDesc";

const GENRE_OPTIONS = [
  { value: "earlyMusic", label: "Early Music" },
  { value: "baroque", label: "Baroque" },
  { value: "classical", label: "Classical" },
  { value: "romantic", label: "Romantic" },
  { value: "contemporary", label: "Contemporary" },
  { value: "worldMusic", label: "World Music" },
  { value: "jazz", label: "Jazz" },
  { value: "crossover", label: "Crossover" },
  { value: "electronic", label: "Electronic" },
  { value: "minimal", label: "Minimal" },
  { value: "popRock", label: "Pop / Rock" },
];

const INSTRUMENTATION_OPTIONS = [
  { value: "solo", label: "Solo" },
  { value: "chamber", label: "Chamber" },
  { value: "ensemble", label: "Ensemble" },
  { value: "orchestra", label: "Orchestral" },
  { value: "vocalChoral", label: "Vocal / Choral" },
];

const FILTER_GROUPS: FilterGroup[] = [
  { label: "Genre", param: "genre", options: GENRE_OPTIONS },
  { label: "Instrumentation", param: "instrumentation", options: INSTRUMENTATION_OPTIONS },
];

const VALID_GENRES = new Set(GENRE_OPTIONS.map((o) => o.value));
const VALID_INSTRUMENTATIONS = new Set(INSTRUMENTATION_OPTIONS.map((o) => o.value));

function parseFilterParam(raw: string | undefined, valid: Set<string>): string[] {
  if (!raw) return [];
  return raw.split(",").filter((v) => valid.has(v));
}

const SORT_OPTIONS: SortOption<SortMode>[] = [
  { value: "titleAsc", label: "Title", iconDirection: "asc" },
  { value: "titleDesc", label: "Title", iconDirection: "desc" },
  { value: "catalogNoAsc", label: "Cat. No.", iconDirection: "asc" },
  { value: "catalogNoDesc", label: "Cat. No.", iconDirection: "desc" },
  { value: "releaseDateAsc", label: "Release date", iconDirection: "asc" },
  { value: "releaseDateDesc", label: "Release date", iconDirection: "desc" },
];

function normalizeSort(s: string | undefined): SortMode {
  switch (s) {
    case "titleAsc":
    case "titleDesc":
    case "catalogNoAsc":
    case "catalogNoDesc":
    case "releaseDateAsc":
    case "releaseDateDesc":
      return s;
    default:
      return "releaseDateDesc";
  }
}

const RELEASE_FILTER_CLAUSE = `
_type == "release" &&
(
  $q == "" ||
  name match $qPattern ||
  albumArtist match $qPattern ||
  catalogNo match $qPattern
) &&
(count($genres) == 0 || count(genre[@ in $genres]) > 0) &&
(count($instrumentations) == 0 || count(instrumentation[@ in $instrumentations]) > 0)
`;

const RELEASE_PROJECTION = `{
  _id,
  name,
  albumArtist,
  catalogNo,
  releaseDate,
  "slug": slug.current,
  albumCover
}`;

const RELEASES_BY_TITLE_ASC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(lower(name) asc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_BY_TITLE_DESC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(lower(name) desc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_BY_CATALOG_NO_ASC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(lower(catalogNo) asc, lower(name) asc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_BY_CATALOG_NO_DESC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(lower(catalogNo) desc, lower(name) asc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_BY_DATE_ASC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(coalesce(releaseDate, "9999-12-31") asc, lower(name) asc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_BY_DATE_DESC_QUERY = defineQuery(`
*[
  ${RELEASE_FILTER_CLAUSE}
]
| order(coalesce(releaseDate, "0000-01-01") desc, lower(name) asc)
[$start...$end]${RELEASE_PROJECTION}
`);

const RELEASES_COUNT_QUERY = defineQuery(`
count(*[
  ${RELEASE_FILTER_CLAUSE}
])
`);

export const metadata: Metadata = {
  title: "Releases",
  description:
    "Explore the full TRPTK catalogue. Filter by genre and instrumentation to find your next favourite recording.",
};

export default async function ReleasesPage({
  searchParams,
}: {
  searchParams: Promise<{
    page?: string;
    q?: string;
    sort?: string;
    genre?: string;
    instrumentation?: string;
  }>;
}) {
  const sp = await searchParams;

  const q = normalizeQuery(sp.q);
  const sort = normalizeSort(sp.sort);
  const page = clampInt(sp.page, 1, 1, 9999);
  const genres = parseFilterParam(sp.genre, VALID_GENRES);
  const instrumentations = parseFilterParam(sp.instrumentation, VALID_INSTRUMENTATIONS);

  const start = (page - 1) * PAGE_SIZE;
  const end = start + PAGE_SIZE;

  const qPattern = q ? `${groqLikeParam(q)}*` : "";

  const listQuery =
    sort === "titleDesc"
      ? RELEASES_BY_TITLE_DESC_QUERY
      : sort === "catalogNoAsc"
        ? RELEASES_BY_CATALOG_NO_ASC_QUERY
        : sort === "catalogNoDesc"
          ? RELEASES_BY_CATALOG_NO_DESC_QUERY
          : sort === "releaseDateAsc"
            ? RELEASES_BY_DATE_ASC_QUERY
            : sort === "releaseDateDesc"
              ? RELEASES_BY_DATE_DESC_QUERY
              : RELEASES_BY_TITLE_ASC_QUERY;

  const queryParams = { start, end, q, qPattern, genres, instrumentations };

  const [releases, total] = await Promise.all([
    sanity.fetch<ReleaseCardData[]>(listQuery, queryParams),
    sanity.fetch<number>(RELEASES_COUNT_QUERY, queryParams),
  ]);

  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
  const safePage = Math.min(page, totalPages);

  const initialFilters: Record<string, string[]> = {};
  if (genres.length) initialFilters.genre = genres;
  if (instrumentations.length) initialFilters.instrumentation = instrumentations;

  const buildHref = (nextPage: number) => {
    const params = new URLSearchParams();
    if (q) params.set("q", q);
    if (sort !== "releaseDateDesc") params.set("sort", sort);
    if (genres.length) params.set("genre", genres.join(","));
    if (instrumentations.length) params.set("instrumentation", instrumentations.join(","));
    if (nextPage > 1) params.set("page", String(nextPage));
    const qs = params.toString();
    return qs ? `/releases?${qs}` : "/releases";
  };

  return (
    <main className="mx-auto my-auto max-w-300 px-6 py-12 font-silka md:px-8 md:py-16 2xl:max-w-400">
      <div className="mb-10">
        <AnimatedText text="Releases" as="h1" className="font-argesta text-3xl" />
        <p className="mt-2 text-base text-lightsec dark:text-darksec">
          {total ? `${total} release(s)` : "No releases found."}
        </p>
      </div>

      <div className="mb-12">
        <SearchBar
          initialQuery={q}
          initialSort={sort}
          initialPage={safePage}
          defaultSort="releaseDateDesc"
          placeholder="Search releases…"
          sortOptions={SORT_OPTIONS}
          sortAriaLabel="Sort releases"
          filterGroups={FILTER_GROUPS}
          initialFilters={initialFilters}
        />
      </div>

      <section className={CARD_GRID_CLASSES_4}>
        {releases.map((release) => (
          <ReleaseCard key={release._id} release={release} />
        ))}
      </section>

      {totalPages > 1 ? (
        <PaginationNav page={safePage} totalPages={totalPages} buildHref={buildHref} />
      ) : null}
    </main>
  );
}
