"use client";

import { useCallback, useMemo, useState } from "react";
import type { SanityImageSource } from "@sanity/image-url";
import { IoCloseOutline } from "react-icons/io5";
import {
  HiOutlineChevronDoubleLeft,
  HiOutlineChevronLeft,
  HiOutlineChevronRight,
  HiOutlineChevronDoubleRight,
} from "react-icons/hi2";
import { ReleaseCard } from "@/components/release/ReleaseCard";
import { SortDropdown, type SortOption } from "@/components/SortDropdown";
import { FilterDropdown, type FilterGroup } from "@/components/FilterDropdown";
import { IconButton } from "@/components/IconButton";
import { CARD_GRID_CLASSES_3 } from "@/lib/constants";

export type ArtistRelease = {
  _id?: string;
  name?: string;
  albumArtist?: string;
  catalogNo?: string;
  releaseDate?: string;
  slug?: string;
  albumCover?: SanityImageSource;
  genre?: string[];
  instrumentation?: string[];
};

const PAGE_SIZE = 12;

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

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" },
];

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 },
];

function compareStr(a?: string, b?: string): number {
  return (a ?? "").localeCompare(b ?? "", undefined, { sensitivity: "base" });
}

function compareDate(a?: string, b?: string, asc = true): number {
  const da = a ?? (asc ? "9999-12-31" : "0000-01-01");
  const db = b ?? (asc ? "9999-12-31" : "0000-01-01");
  return da < db ? -1 : da > db ? 1 : 0;
}

function sortReleases(list: ArtistRelease[], mode: SortMode): ArtistRelease[] {
  return [...list].sort((a, b) => {
    switch (mode) {
      case "titleAsc":
        return compareStr(a.name, b.name);
      case "titleDesc":
        return compareStr(b.name, a.name);
      case "catalogNoAsc":
        return compareStr(a.catalogNo, b.catalogNo) || compareStr(a.name, b.name);
      case "catalogNoDesc":
        return compareStr(b.catalogNo, a.catalogNo) || compareStr(a.name, b.name);
      case "releaseDateAsc":
        return compareDate(a.releaseDate, b.releaseDate, true) || compareStr(a.name, b.name);
      case "releaseDateDesc":
        return compareDate(b.releaseDate, a.releaseDate, false) || compareStr(a.name, b.name);
    }
  });
}

function matchesSearch(r: ArtistRelease, lower: string): boolean {
  return (
    (r.name?.toLowerCase().includes(lower) ?? false) ||
    (r.albumArtist?.toLowerCase().includes(lower) ?? false) ||
    (r.catalogNo?.toLowerCase().includes(lower) ?? false)
  );
}

function matchesFilters(r: ArtistRelease, filters: Record<string, string[]>): boolean {
  const genres = filters.genre ?? [];
  const instrumentations = filters.instrumentation ?? [];

  if (genres.length > 0 && !genres.some((g) => r.genre?.includes(g))) return false;
  if (instrumentations.length > 0 && !instrumentations.some((i) => r.instrumentation?.includes(i)))
    return false;

  return true;
}

type Props = {
  releases: ArtistRelease[];
};

export function ArtistReleasesTab({ releases }: Props) {
  const [q, setQ] = useState("");
  const [sort, setSort] = useState<SortMode>("releaseDateDesc");
  const [filters, setFilters] = useState<Record<string, string[]>>({});
  const [page, setPage] = useState(1);

  const handleFilterChange = useCallback((param: string, selected: string[]) => {
    setFilters((prev) => ({ ...prev, [param]: selected }));
    setPage(1);
  }, []);

  const handleSortChange = useCallback((value: SortMode) => {
    setSort(value);
    setPage(1);
  }, []);

  const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setQ(e.target.value);
    setPage(1);
  }, []);

  const filtered = useMemo(() => {
    const lower = q.trim().toLowerCase();

    let result = releases;
    if (lower) result = result.filter((r) => matchesSearch(r, lower));
    result = result.filter((r) => matchesFilters(r, filters));

    return sortReleases(result, sort);
  }, [releases, q, sort, filters]);

  const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const safePage = Math.min(page, totalPages);
  const start = (safePage - 1) * PAGE_SIZE;
  const paginated = filtered.slice(start, start + PAGE_SIZE);

  return (
    <div>
      <div className="mb-4">
        <p className="text-sm text-lightsec dark:text-darksec">
          {filtered.length ? `${filtered.length} release(s)` : "No releases found."}
        </p>
      </div>

      <div className="mb-12 flex items-center gap-3">
        <input
          value={q}
          onChange={handleSearchChange}
          placeholder="Search releases…"
          className="no-ring w-full rounded-xl border border-lightline px-6 py-3 text-lighttext shadow-lg transition-all duration-200 ease-in-out hover:border-lightline-hover hover:text-trptkblue focus:border-lightline-focus dark:border-darkline dark:text-darktext dark:hover:border-darkline-hover dark:hover:text-white dark:focus:border-darkline-focus"
          aria-label="Search releases"
        />

        {q ? (
          <IconButton
            onClick={() => {
              setQ("");
              setPage(1);
            }}
            className="text-lg"
            aria-label="Clear search"
          >
            <IoCloseOutline />
          </IconButton>
        ) : null}

        <FilterDropdown groups={FILTER_GROUPS} values={filters} onChange={handleFilterChange} />

        <SortDropdown
          options={SORT_OPTIONS}
          value={sort}
          onChange={handleSortChange}
          ariaLabel="Sort releases"
        />
      </div>

      {paginated.length > 0 ? (
        <section className={CARD_GRID_CLASSES_3}>
          {paginated.map((r) => (
            <ReleaseCard key={r._id ?? r.slug} release={r} />
          ))}
        </section>
      ) : null}

      {totalPages > 1 ? (
        <Pagination page={safePage} totalPages={totalPages} onPageChange={setPage} />
      ) : null}
    </div>
  );
}

function Pagination({
  page,
  totalPages,
  onPageChange,
}: {
  page: number;
  totalPages: number;
  onPageChange: (p: number) => void;
}) {
  const hasPrev = page > 1;
  const hasNext = page < totalPages;

  return (
    <nav aria-label="Pagination" className="mt-12 flex items-center justify-between">
      <div className="text-sm text-lightsec dark:text-darksec">
        Page {page} of {totalPages}
      </div>

      <div className="flex gap-3 text-lg">
        <IconButton disabled={!hasPrev} onClick={() => onPageChange(1)} aria-label="First page">
          <HiOutlineChevronDoubleLeft />
        </IconButton>
        <IconButton
          disabled={!hasPrev}
          onClick={() => onPageChange(page - 1)}
          aria-label="Previous page"
        >
          <HiOutlineChevronLeft />
        </IconButton>
        <IconButton
          disabled={!hasNext}
          onClick={() => onPageChange(page + 1)}
          aria-label="Next page"
        >
          <HiOutlineChevronRight />
        </IconButton>
        <IconButton
          disabled={!hasNext}
          onClick={() => onPageChange(totalPages)}
          aria-label="Last page"
        >
          <HiOutlineChevronDoubleRight />
        </IconButton>
      </div>
    </nav>
  );
}
