import React, { useState, useEffect } from "react";
import { Squares2X2Icon, Bars3Icon } from "@heroicons/react/24/solid";
import type { CursorObj } from "../../api";

export type ListViewProps<T> = {
  fetchItems: (cursor: string, limit: number) => Promise<{ items: T[]; cursor: CursorObj}>;
  renderItem: (item: T, layout: "square" | "horizontal") => React.ReactNode;
  pageSize?: number;
  searchPlaceholder?: string;
  setSearch: any;
};

export function ListView<T>({
  fetchItems,
  renderItem,
  pageSize = 20,
  searchPlaceholder = "Search...",
}: ListViewProps<T>) {
  const [items, setItems] = useState<T[]>([]);
  const [cursorObj, setCursorObj] = useState<CursorObj | undefined>(undefined);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [search, setSearch] = useState("");
  const [layout, setLayout] = useState<"square" | "horizontal">("horizontal");
  const [error, setError] = useState<string | null>(null);

  const loadItems = async (reset: boolean = false) => {
    try {
      if (reset) {
        setLoading(true);
        setCursorObj(undefined);
      } else {
        setLoadingMore(true);
      }

      const cursorStr = cursorObj ? btoa(JSON.stringify(cursorObj)) : ""
      console.log("encoded cursor: " + cursorStr)
      
      const result = await fetchItems(cursorStr, pageSize);

      if (reset) setItems(result.items);
      else setItems(prev => [...prev, ...result.items]);

      setCursorObj(result.cursor);
      setError(null);
    } catch (err: any) {
      console.error(err);
      setError("Failed to fetch items.");
    } finally {
      setLoading(false);
      setLoadingMore(false);
    }
  };

  useEffect(() => {
    loadItems(true);
  }, [search]);

  return (
    <div className="w-full min-h-screen bg-gray-50 p-6 text-black flex flex-col items-center">
      <div className="w-full sm:w-4/5 flex gap-4 mb-8">
        <input
          type="text"
          placeholder={searchPlaceholder}
          // value={search}
          onChange={e => setSearch(e.target.value)}
          className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-black"
        />
        <button
          className="p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"
          onClick={() =>
            setLayout(prev => (prev === "square" ? "horizontal" : "square"))
          }>
          {layout === "square" ? <Squares2X2Icon className="w-6 h-6" /> : <Bars3Icon className="w-6 h-6" />}
        </button>
      </div>

      {error && <div className="text-red-600 mb-6 font-medium">{error}</div>}

      <div
        className={`w-full sm:w-4/5 grid gap-6 ${
          layout === "square" ? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4" : "grid-cols-1"
        }`}
      >
        {items.map(item => renderItem(item, layout))}
      </div>

      {cursorObj && (
        <div className="mt-8 flex justify-center w-full sm:w-4/5">
          <button
            className="px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
            onClick={() => loadItems(false)}
            disabled={loadingMore}
          >
            {loadingMore ? "Loading..." : "Load More"}
          </button>
        </div>
      )}

      {loading && <div className="mt-20 font-medium">Loading...</div>}
    </div>
  );
}
