import type { Metadata } from "next";
import { defineQuery } from "next-sanity";
import { sanity } from "@/lib/sanity";
import { BlogCard, type BlogCardData } from "@/components/blog/BlogCard";
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 = "dateDesc" | "dateAsc";

const CATEGORY_OPTIONS = [
  { value: "News", label: "News" },
  { value: "Behind the Scenes", label: "Behind the Scenes" },
  { value: "Music History", label: "Music History" },
  { value: "Tech Talk", label: "Tech Talk" },
];

const FILTER_GROUPS: FilterGroup[] = [
  { label: "Category", param: "category", options: CATEGORY_OPTIONS },
];

const VALID_CATEGORIES = new Set(CATEGORY_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: "dateDesc", label: "Date", iconDirection: "desc" },
  { value: "dateAsc", label: "Date", iconDirection: "asc" },
];

function normalizeSort(s: string | undefined): SortMode {
  return s === "dateAsc" ? "dateAsc" : "dateDesc";
}

const BLOG_FILTER_CLAUSE = `
_type == "blog" &&
(
  $q == "" ||
  title match $qPattern ||
  subtitle match $qPattern ||
  author match $qPattern
) &&
(count($categories) == 0 || category in $categories)
`;

const BLOG_PROJECTION = `{
  _id,
  title,
  subtitle,
  author,
  publishDate,
  category,
  "slug": slug.current,
  featuredImage
}`;

const BLOGS_BY_DATE_DESC_QUERY = defineQuery(`
*[
  ${BLOG_FILTER_CLAUSE}
]
| order(coalesce(publishDate, "0000-01-01") desc, lower(title) asc)
[$start...$end]${BLOG_PROJECTION}
`);

const BLOGS_BY_DATE_ASC_QUERY = defineQuery(`
*[
  ${BLOG_FILTER_CLAUSE}
]
| order(coalesce(publishDate, "9999-12-31") asc, lower(title) asc)
[$start...$end]${BLOG_PROJECTION}
`);

const BLOGS_COUNT_QUERY = defineQuery(`
count(*[
  ${BLOG_FILTER_CLAUSE}
])
`);

export const metadata: Metadata = {
  title: "Blog",
  description:
    "News, behind-the-scenes stories, and insights from TRPTK.",
};

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

  const q = normalizeQuery(sp.q);
  const sort = normalizeSort(sp.sort);
  const page = clampInt(sp.page, 1, 1, 9999);
  const categories = parseFilterParam(sp.category, VALID_CATEGORIES);

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

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

  const listQuery = sort === "dateAsc" ? BLOGS_BY_DATE_ASC_QUERY : BLOGS_BY_DATE_DESC_QUERY;

  const queryParams = { start, end, q, qPattern, categories };

  const [blogs, total] = await Promise.all([
    sanity.fetch<BlogCardData[]>(listQuery, queryParams),
    sanity.fetch<number>(BLOGS_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 (categories.length) initialFilters.category = categories;

  const buildHref = (nextPage: number) => {
    const params = new URLSearchParams();
    if (q) params.set("q", q);
    if (sort !== "dateDesc") params.set("sort", sort);
    if (categories.length) params.set("category", categories.join(","));
    if (nextPage > 1) params.set("page", String(nextPage));
    const qs = params.toString();
    return qs ? `/blog?${qs}` : "/blog";
  };

  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="Blog" as="h1" className="font-argesta text-3xl" />
        <p className="mt-2 text-base text-lightsec dark:text-darksec">
          {total ? `${total} post(s)` : "No posts found."}
        </p>
      </div>

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

      <section className={CARD_GRID_CLASSES_4}>
        {blogs.map((blog) => (
          <BlogCard key={blog._id} blog={blog} />
        ))}
      </section>

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