import { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { useWatchlist } from "../context/WatchlistContext.jsx";

const STATIC_ASSETS = "https://warframe.market/static/assets";
const PAGE_SIZE = 200;

const CATEGORIES = ["mods", "arcanes", "rivens", "weapons", "warframes", "miscellaneous"];

const WEAPON_TAGS = new Set([
  "weapon", "primary", "secondary", "melee", "rifle", "pistol", "shotgun",
  "archgun", "archmelee", "bow", "sniper", "thrown_melee", "claws",
  "daggers", "dual_daggers", "dual_swords", "fists", "glaives", "hammers",
  "heavy_blade", "machetes", "nikanas", "polearms", "rapiers", "scythes",
  "sparring", "staves", "sword_and_shield", "swords", "tonfas", "whips",
  "blade_and_whip", "gunblade", "nunchaku", "dual_nikanas", "two_handed_nikana",
  "heavy_scythe", "assault_rifle", "sniper", "submachine", "speargun",
  "crossbow", "beam", "kitgun", "zaw", "k_drive", "parazon",
]);

function getItemCategory(item) {
  const tags = item.tags || [];
  if (tags.includes("riven_mod") || tags.includes("riven")) return "rivens";
  if (tags.includes("mod") || tags.includes("augment") || tags.includes("stance")) return "mods";
  if (tags.includes("arcane_enhancement") || tags.includes("arcane_helmet")) return "arcanes";
  if (tags.includes("warframe")) return "warframes";
  if (tags.some((t) => WEAPON_TAGS.has(t))) return "weapons";
  return "miscellaneous";
}

export default function CatalogView() {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [search, setSearch] = useState("");
  const [selectedCats, setSelectedCats] = useState([]);
  const [sortKey, setSortKey] = useState("name");
  const [sortAsc, setSortAsc] = useState(true);
  const [page, setPage] = useState(0);
  const { toggleItem, isWatched } = useWatchlist();

  const [prices, setPrices] = useState({});
  const [pricesLoading, setPricesLoading] = useState(false);
  const [priceProgress, setPriceProgress] = useState({ loaded: 0, total: 0 });
  const bgDoneRef = useRef(false);

  const doStream = useCallback(async (slugs, { label = "", onComplete } = {}) => {
    if (slugs.length === 0) {
      if (onComplete) onComplete();
      return;
    }
    setPricesLoading(true);
    setPriceProgress({ loaded: 0, total: slugs.length });

    let loaded = 0;
    try {
      const res = await fetch("/api/prices/stream", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ slugs }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);

      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });

        const lines = buffer.split("\n");
        buffer = lines.pop();

        for (const line of lines) {
          if (line.startsWith("data: ")) {
            const json = line.slice(6);
            try {
              const batch = JSON.parse(json);
              const count = Object.keys(batch).length;
              if (count > 0) {
                setPrices((prev) => ({ ...prev, ...batch }));
                loaded += count;
                setPriceProgress({ loaded, total: slugs.length });
              }
            } catch {}
          } else if (line.startsWith("event: done")) {
            if (onComplete) onComplete();
            return;
          }
        }
      }
    } catch (err) {
      console.error(label ? `[${label}] ` : "", "Stream price fetch failed:", err);
    } finally {
      setPricesLoading(false);
    }
  }, []);

  useEffect(() => {
    let cancelled = false;
    async function fetchItems() {
      setLoading(true);
      setError(null);
      try {
        const res = await fetch("/api/items");
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const data = await res.json();
        if (!cancelled) setItems(data);
      } catch (err) {
        if (!cancelled) setError(err.message);
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    fetchItems();
    return () => { cancelled = true; };
  }, []);

  useEffect(() => {
    if (items.length === 0 || bgDoneRef.current) return;
    const slugs = items.map((item) => item.slug);
    doStream(slugs, {
      label: "bg",
      onComplete: () => { bgDoneRef.current = true; },
    });
  }, [items, doStream]);

  const filtered = useMemo(() => {
    let list = items;
    if (search) {
      const q = search.toLowerCase();
      list = list.filter((item) => {
        const name = item.i18n?.en?.name || "";
        return name.toLowerCase().includes(q);
      });
    }
    if (selectedCats.length > 0) {
      list = list.filter((item) =>
        selectedCats.includes(getItemCategory(item))
      );
    }
    return list;
  }, [items, search, selectedCats]);

  const sorted = useMemo(() => {
    let list = [...filtered];
    if (sortKey === "platinum") {
      const priced = [];
      const unpriced = [];
      for (const item of list) {
        const p = prices[item.slug];
        if (p?.lowestSell != null && p?.highestBuy != null) priced.push(item);
        else unpriced.push(item);
      }
      priced.sort((a, b) => prices[a.slug].lowestSell - prices[b.slug].lowestSell);
      if (!sortAsc) priced.reverse();
      unpriced.sort((a, b) => (a.i18n?.en?.name || "").localeCompare(b.i18n?.en?.name || ""));
      return [...priced, ...unpriced];
    }
    list.sort((a, b) => {
      let va, vb;
      if (sortKey === "name") {
        va = a.i18n?.en?.name || "";
        vb = b.i18n?.en?.name || "";
      } else if (sortKey === "category") {
        va = getItemCategory(a);
        vb = getItemCategory(b);
      } else {
        va = a.id;
        vb = b.id;
      }
      if (va < vb) return sortAsc ? -1 : 1;
      if (va > vb) return sortAsc ? 1 : -1;
      return 0;
    });
    return list;
  }, [filtered, sortKey, sortAsc, prices]);

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

  function handleSort(key) {
    if (sortKey === key) setSortAsc(!sortAsc);
    else { setSortKey(key); setSortAsc(true); }
    setPage(0);
  }

  function toggleCat(cat) {
    setSelectedCats((prev) =>
      prev.includes(cat) ? prev.filter((c) => c !== cat) : [...prev, cat]
    );
    setPage(0);
  }

  const sortArrow = (key) => {
    if (sortKey !== key) return "";
    return <span className="sort-arrow">{sortAsc ? "\u25B2" : "\u25BC"}</span>;
  };

  if (loading) {
    return (
      <div className="loading">
        <div className="spinner" /> Loading item catalog...
      </div>
    );
  }

  if (error) {
    return (
      <div className="error-box">
        <p>Failed to load catalog: {error}</p>
        <button onClick={() => window.location.reload()}>Retry</button>
      </div>
    );
  }

  const pricedCount = Object.keys(prices).length;
  const pricedPercent = items.length > 0 ? Math.round((pricedCount / items.length) * 100) : 0;

  return (
    <div>
      {pricesLoading && (
        <div className="progress-bar-wrap">
          <div className="progress-bar">
            <div className="progress-bar-fill" style={{ width: `${pricedPercent}%` }} />
          </div>
          <span className="progress-text">
            Loading prices... {priceProgress.loaded}/{priceProgress.total} ({pricedPercent}%)
          </span>
        </div>
      )}
      <div className="controls">
        <input
          className="search-box"
          type="text"
          placeholder="Search items..."
          value={search}
          onChange={(e) => { setSearch(e.target.value); setPage(0); }}
        />
        <button
          className={`tab-btn${sortKey === "platinum" ? " active" : ""}`}
          onClick={() => handleSort("platinum")}
        >
          {pricesLoading ? `Loading... ${pricedPercent}%` : pricedCount > 0 ? "Sort by Platinum \u2713" : "Sort by Platinum"}
        </button>
      </div>
      <div className="controls">
        <div className="tag-filters">
          {CATEGORIES.map((cat) => (
            <button
              key={cat}
              className={`tag-btn${selectedCats.includes(cat) ? " active" : ""}`}
              onClick={() => toggleCat(cat)}
            >
              {cat}
            </button>
          ))}
        </div>
      </div>
      <div className="table-wrap">
        <table>
          <thead>
            <tr>
              <th style={{ width: 40 }}></th>
              <th onClick={() => handleSort("name")}>
                Name{sortArrow("name")}
              </th>
              <th onClick={() => handleSort("category")}>
                Category{sortArrow("category")}
              </th>
              <th onClick={() => handleSort("platinum")}>
                Platinum{sortArrow("platinum")}
              </th>
            </tr>
          </thead>
          <tbody>
            {pageItems.map((item) => {
              const name = item.i18n?.en?.name || item.slug;
              const thumb = item.i18n?.en?.thumb;
              const p = prices[item.slug];
              return (
                <tr key={item.id}>
                  <td>
                    <button
                      className={`star-btn${isWatched(item.slug) ? " starred" : ""}`}
                      onClick={() => toggleItem(item.slug)}
                      title={isWatched(item.slug) ? "Remove from watchlist" : "Add to watchlist"}
                    >
                      {isWatched(item.slug) ? "\u2605" : "\u2606"}
                    </button>
                  </td>
                  <td>
                    <div className="item-name">
                      {thumb && (
                        <img
                          className="item-thumb"
                          src={`${STATIC_ASSETS}/${thumb}`}
                          alt=""
                          loading="lazy"
                        />
                      )}
                      <span>{name}</span>
                    </div>
                  </td>
                  <td>
                    <span className="tag-badge">
                      {getItemCategory(item)}
                    </span>
                  </td>
                  <td className="price-sell">
                    {p?.lowestSell != null ? `${p.lowestSell}\u25BC` : "\u2014"}
                  </td>
                </tr>
              );
            })}
            {sorted.length === 0 && (
              <tr>
                <td colSpan={4} className="empty-msg">
                  No items match your filters.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>
      {totalPages > 1 && (
        <div className="pagination">
          <button
            className="tab-btn"
            disabled={safePage === 0}
            onClick={() => setPage(safePage - 1)}
          >
            &larr; Prev
          </button>
          <span className="page-info">
            Page {safePage + 1} of {totalPages} ({sorted.length} items)
          </span>
          <button
            className="tab-btn"
            disabled={safePage >= totalPages - 1}
            onClick={() => setPage(safePage + 1)}
          >
            Next &rarr;
          </button>
        </div>
      )}
    </div>
  );
}
