"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { IoCloseOutline } from "react-icons/io5";
import {
  HiOutlineChevronDoubleLeft,
  HiOutlineChevronLeft,
  HiOutlineChevronRight,
  HiOutlineChevronDoubleRight,
} from "react-icons/hi2";
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";
import {
  DownloadCard,
  UpcomingCard,
  type DownloadCardData,
  type UpcomingCardData,
} from "./DownloadCard";

const PAGE_SIZE = 12;

// ── Sort ────────────────────────────────────────────────────────────

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

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

// ── Filters ─────────────────────────────────────────────────────────

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

// ── Helpers ─────────────────────────────────────────────────────────

type Sortable = {
  product_title: string;
  catalogNo?: string | null;
  releaseDate?: string | null;
};

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

function compareDate(a?: string | null, b?: string | null, 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 sortItems<T extends Sortable>(list: T[], mode: SortMode): T[] {
  return [...list].sort((a, b) => {
    switch (mode) {
      case "titleAsc":
        return compareStr(a.product_title, b.product_title);
      case "titleDesc":
        return compareStr(b.product_title, a.product_title);
      case "catalogNoAsc":
        return compareStr(a.catalogNo, b.catalogNo) || compareStr(a.product_title, b.product_title);
      case "catalogNoDesc":
        return compareStr(b.catalogNo, a.catalogNo) || compareStr(a.product_title, b.product_title);
      case "releaseDateAsc":
        return (
          compareDate(a.releaseDate, b.releaseDate, true) ||
          compareStr(a.product_title, b.product_title)
        );
      case "releaseDateDesc":
        return (
          compareDate(b.releaseDate, a.releaseDate, false) ||
          compareStr(a.product_title, b.product_title)
        );
    }
  });
}

type Searchable = {
  product_title: string;
  albumArtist?: string | null;
  catalogNo?: string | null;
};

function matchesSearch(item: Searchable, lower: string): boolean {
  return (
    item.product_title.toLowerCase().includes(lower) ||
    (item.albumArtist?.toLowerCase().includes(lower) ?? false) ||
    (item.catalogNo?.toLowerCase().includes(lower) ?? false)
  );
}

type Filterable = {
  genre?: string[];
  instrumentation?: string[];
};

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

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

  return true;
}

// ── Component ───────────────────────────────────────────────────────

export function DownloadsTab() {
  const [downloads, setDownloads] = useState<DownloadCardData[]>([]);
  const [upcoming, setUpcoming] = useState<UpcomingCardData[]>([]);
  const [loading, setLoading] = useState(true);

  const [q, setQ] = useState("");
  const [sort, setSort] = useState<SortMode>("releaseDateDesc");
  const [filters, setFilters] = useState<Record<string, string[]>>({});
  const [dlPage, setDlPage] = useState(1);
  const [upPage, setUpPage] = useState(1);

  useEffect(() => {
    async function fetchDownloads() {
      try {
        const res = await fetch("/api/account/downloads");
        if (res.ok) {
          const data = await res.json();
          if (data.downloads?.length) setDownloads(data.downloads);
          if (data.upcoming?.length) setUpcoming(data.upcoming);
        }
      } catch {
        // Silently fail
      } finally {
        setLoading(false);
      }
    }
    fetchDownloads();
  }, []);

  const resetPages = useCallback(() => {
    setDlPage(1);
    setUpPage(1);
  }, []);

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

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

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

  const clearSearch = useCallback(() => {
    setQ("");
    resetPages();
  }, [resetPages]);

  const filteredDownloads = useMemo(() => {
    const lower = q.trim().toLowerCase();
    let result = downloads;
    if (lower) result = result.filter((d) => matchesSearch(d, lower));
    result = result.filter((d) => matchesFilters(d, filters));
    return sortItems(result, sort);
  }, [downloads, q, sort, filters]);

  const filteredUpcoming = useMemo(() => {
    const lower = q.trim().toLowerCase();
    let result = upcoming;
    if (lower) result = result.filter((u) => matchesSearch(u, lower));
    result = result.filter((u) => matchesFilters(u, filters));
    return sortItems(result, sort);
  }, [upcoming, q, sort, filters]);

  const dlTotalPages = Math.max(1, Math.ceil(filteredDownloads.length / PAGE_SIZE));
  const dlSafePage = Math.min(dlPage, dlTotalPages);
  const dlStart = (dlSafePage - 1) * PAGE_SIZE;
  const paginatedDownloads = filteredDownloads.slice(dlStart, dlStart + PAGE_SIZE);

  const upTotalPages = Math.max(1, Math.ceil(filteredUpcoming.length / PAGE_SIZE));
  const upSafePage = Math.min(upPage, upTotalPages);
  const upStart = (upSafePage - 1) * PAGE_SIZE;
  const paginatedUpcoming = filteredUpcoming.slice(upStart, upStart + PAGE_SIZE);

  if (loading) {
    return <p className="py-12 text-center text-lightsec dark:text-darksec">Loading downloads…</p>;
  }

  if (downloads.length === 0 && upcoming.length === 0) {
    return (
      <p className="py-12 text-center text-lightsec dark:text-darksec">
        No downloads available. Your digital purchases will appear here.
      </p>
    );
  }

  const totalFiltered = filteredDownloads.length + filteredUpcoming.length;

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

      {/* Search + Filter + Sort bar */}
      <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={clearSearch} 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>

      {/* Available Downloads */}
      {paginatedDownloads.length > 0 && (
        <section>
          <div className={CARD_GRID_CLASSES_3}>
            {paginatedDownloads.map((dl) => (
              <DownloadCard key={dl.product_title} item={dl} />
            ))}
          </div>

          {dlTotalPages > 1 && (
            <Pagination page={dlSafePage} totalPages={dlTotalPages} onPageChange={setDlPage} />
          )}
        </section>
      )}

      {/* Upcoming Releases */}
      {paginatedUpcoming.length > 0 && (
        <section className={paginatedDownloads.length > 0 ? "mt-16" : ""}>
          <div className="mb-4">
            <h2 className="font-silkasb text-sm tracking-wider uppercase">Upcoming Releases</h2>
            <p className="mt-1 text-xs text-lightsec dark:text-darksec">
              You&apos;ll receive download links by email when these become available.
            </p>
          </div>

          <div className={CARD_GRID_CLASSES_3}>
            {paginatedUpcoming.map((up) => (
              <UpcomingCard key={up.product_title} item={up} />
            ))}
          </div>

          {upTotalPages > 1 && (
            <Pagination page={upSafePage} totalPages={upTotalPages} onPageChange={setUpPage} />
          )}
        </section>
      )}

      {/* No results after filtering */}
      {totalFiltered === 0 && (q || Object.values(filters).some((v) => v.length > 0)) && (
        <p className="py-12 text-center text-lightsec dark:text-darksec">No releases found.</p>
      )}
    </div>
  );
}

// ── Pagination ──────────────────────────────────────────────────────

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>
  );
}
